在WPF中模拟主页概念时的逻辑错误

时间:2016-03-31 17:03:52

标签: c# wpf generics mvvm user-controls

我试图在WPF Window s上模拟ASP.Net主页概念(MVC中的布局)。

我有一个CustomWindow类,为这类Window s指定了一些行为:

public class CustomWindow : Window
{
    //...
}

MasterWindowBase;一个CustomWindow,它将某种UserControl作为窗口内容(通过样式):

public abstract class MasterWindowBase : CustomWindow
{
    public MasterWindowBase(MyUserControlBase content)
    {
        ContentUserControl = content;
        Style = Application.Current.FindResource("MasterWindowStyle") as Style;
    }

    #region ContentUserControl Property
    public MyUserControlBase ContentUserControl
    {
        get { return (MyUserControlBase)GetValue(ContentUserControlProperty); }
        set { SetValue(ContentUserControlProperty, value); }
    }

    public static readonly DependencyProperty ContentUserControlProperty =
        DependencyProperty.Register("ContentUserControl", typeof(MyUserControlBase), typeof(MasterWindowBase));
    #endregion
}

应用程序资源中定义的样式:

        <Style x:Key="MasterWindowStyle" TargetType="{x:Type local:MasterWindowBase}">
            <Setter Property="Content">
                <Setter.Value>
                    <Grid>
                        <StackPanel>
                            <TextBlock Text="This is a master window"/>
                            <ContentPresenter Content="{Binding ContentUserControl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MasterWindowBase}}}"/>
                        </StackPanel>
                    </Grid>
                </Setter.Value>
            </Setter>
        </Style>

MasterWindow;用于创建具有指定MasterWindowBase类型的UserControl实例的通用窗口:

public class MasterWindow<TMyUserControlBase>
    : MasterWindowBase
    where TMyUserControlBase : MyUserControlBase, new()
{
    public MasterWindow() : base(new TMyUserControlBase()) { }
}

现在第一个Window.Show,一切都很完美,但后来我发现了两个逻辑错误:

  1. 当我关闭窗口并使用不同的UserControl显示其新实例时,它会加载第一个显示MasterWindow的内容。
  2. 当我显示MasterWindow的新实例时,使用相同的UserControl或使用不同的实例而不关闭当前显示的窗口,它会清除当前显示的所有内容MasterWindow个实例,并在新实例中加载首先显示的MasterWindow的内容。
  3. 请注意,我无法在Template样式中使用MasterWindowStyle属性,因为该样式实际上基于CustomWindow的样式(在已经使用Template属性的实际项目。

    任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

观察到的行为的原因是您尝试在Style中设置窗口的内容。因为它不是模板 - WPF只会使用UserControl创建一次树。然后,当您反复应用此样式时 - 每次都重复使用相同的可视树(具有相同的,第一个,UserControl)(当然,一个控件不能在不同的父项中使用 - 因此它将从现在托管的位置删除并移动到您应用样式的窗口)。

长话短说 - 你不应该在WPF中通过Style设置内容。要解决您的紧急问题,您只需设置 ContentTemplate 属性而不是Content,并将您在DataTemplate中的内容包装起来(其他所有内容都相同)。这将解决它,因为对于模板,每次都会创建新的可视化树。

这是修复它的另一种方法,仍然使用Content属性,但它看起来像是一种黑客攻击而且我最好无效(尽管仍然有效):

<Application.Resources>
    <Grid x:Shared="False" x:Key="myControl">
        <StackPanel>
            <TextBlock Text="This is a master window"/>
            <ContentPresenter Content="{Binding ContentUserControl, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MasterWindowBase}}}"/>
        </StackPanel>
    </Grid>
    <Style x:Key="MasterWindowStyle" TargetType="{x:Type local:MasterWindowBase}">
        <Setter Property="Content">
            <Setter.Value>
                <StaticResource ResourceKey="myControl" />
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>

在这里,您可以使用x:Shared =&#34; False&#34;在资源中定义可视树。属性。此属性表示每次引用此资源时 - 将创建新实例(默认情况下 - 重用相同的实例)。然后在Style中引用此资源。