WPF窗口隐藏内容DependencyProperty

问题描述 投票:1回答:1

我想创建一个Window,重新声明它自己的DependencyProperty名为Content

public partial class InfoWindow : Window
{
    public static new readonly DependencyProperty ContentProperty = DependencyProperty.Register("Content", typeof(object), typeof(InfoWindow), new PropertyMetadata(null));
    public object Content
    {
        get { return GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }
}

并且XAML绑定此属性

<ContentControl Content="{Binding ElementName=_this, Path=Content}" />

它工作正常,只是Visual Studio Designer抱怨Logical tree depth exceeded while traversing the tree. This could indicate a cycle in the tree.

有没有办法告诉设计师绑定是InfoWindow.Content而不是Window.Content?或隐藏房产是一个坏主意,我应该重命名我的财产?

c# wpf dependency-properties
1个回答
0
投票

我在这里想要实现的是动态定义按钮的想法,这些按钮用于显示导航到不同表单的不同视图。 (见下文:)视图和视图模型之间的链接是在Dictionary View_ViewModel中设置的,用于标识按下按钮时为当前视图设置的视图。 (注意:我试图使用最基本的对象来避免使用IOC容器等,以便更容易理解代码)要记住的最重要的事情是正确设置DataContext,否则你将获得逻辑树深度遍历树时超出。错误。您可以在View后面的代码中或在XAML内部执行此操作。例:

public partial class SetupForm : UserControl
{
    public SetupForm()
    {
        InitializeComponent();
        DataContext = new SetupFormVM();
    }
}

要么

<UserControl.DataContext>
    <SaleVM:SalesEntryVM />
</UserControl.DataContext>

这是一个代码片段,可能会更清楚地解释它,并可能回答您的问题。视图模型定义了主窗口中所需的按钮和视图的数量。这是通过将ItemsControl绑定到View Model类中的列表来实现的。 Button命令受限于View Model类中的ICommand ChangeViewCommand属性,该类评估Button press和.calls ViewChange方法,该方法更改CurrentView(这绑定到XAML中的Content)

这就是我的主要Window xaml的样子。

<Window x:Class="MyNameSpace.Views.ApplicationWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:MyNameSpace.Views"
    mc:Ignorable="d"
    Title="ApplicationWindow" Height="Auto" Width="Auto">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition /> -------------------> repeated five times
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition /> -------------------------> repeated five times
    </Grid.RowDefinitions>
    <DockPanel Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="5" >
        <!-- Bind to List of Pages -->
        <ItemsControl ItemsSource="{Binding ControlItemsNamesList}" DockPanel.Dock="Top" >
            <!-- Stack the buttons horizontally --> The list contains the labels to assign to the buttons
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>            ---------------------------------------> This to stack the buttons Horizontally
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <!-- This looks at the list items and creates a button with ControlName -->
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding ControlName}"
                            Command="{Binding DataContext.ChangeViewCommand, RelativeSource={RelativeSource AncestorType={x:Type Window}}}"  ------> This is important for the Buttons to work Window or ContentControl.
                            CommandParameter="{Binding }"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </DockPanel>
    <ContentControl Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="5" Grid.RowSpan="4"  Content="{Binding CurrentView}"/> ---------> This is where I want the new Windows to appear when I click the button
</Grid>

当我单击主窗口中的按钮时,这就是我的用户控件xaml之一。

<UserControl x:Class="MyNameSpace.Views.SetupForm"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800">
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition /> ------------------- repeated five times
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition/> ------------------- repeated five times
    </Grid.RowDefinitions>
    <DockPanel Grid.Row="0" Grid.Column="0" Grid.RowSpan="5" Background="AliceBlue" Margin="0,0,0,0" >
        <!-- Bind to List of Pages -->
        <ItemsControl ItemsSource="{Binding ControlItemsNamesList}" DockPanel.Dock="Left" >
            <!-- Stack the buttons horizontally -->
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Vertical" />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <!-- This looks at the list items and creates a button with ControlName -->
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding ControlName}"
                            Command="{Binding DataContext.ChangeViewCommand, RelativeSource={RelativeSource AncestorType={x:Type ContentControl}}}"
                            CommandParameter="{Binding }"/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </DockPanel>
    <ContentControl Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="5" Grid.RowSpan="4"  Content="{Binding CurrentView}"/>
</Grid>
</UserControl>

这是主窗口的ViewModel:

using Products.MVVMLibrary;
using Products.MVVMLibrary.Interfaces;
using MyNameSpace.Views;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Controls;
using System.Windows.Input;

namespace MyNameSpace.ViewModel
{
public class ApplicationVM : ObservableObject
{
    private MyNameSpace IControlItem currentNavigationItem;
    private MyNameSpace ContentControl currentView;

    private MyNameSpace List<IControlItem> NavigationList;

    private MyNameSpace ICommand changeViewCommand;
    private MyNameSpace ViewConverter viewDictionary;
    private MyNameSpace Dictionary<string, LinkViewToViewModel> View_ViewModel;
    public ApplicationVM()
    {
        viewDictionary = new ViewConverter();
        View_ViewModel = new Dictionary<string, LinkViewToViewModel>();
        NavigationList = new List<IControlItem>();
        InitialiseLists();
    }

    private MyNameSpace void AddControlNavigationItems(string name, ContentControl view, ObservableObject viewModel)
    {
        View_ViewModel.Add(name, new LinkViewToViewModel(view, viewModel));
        IControlItem item = (IControlItem)viewModel;
        NavigationList.Add(item);

    }
    private MyNameSpace void InitialiseLists()
    {
        AddControlNavigationItems("Sales", new SalesForm(), new SalesEntryVM());
        AddControlNavigationItems("Purchases", new PurchaseEntryForm(), new PurchasesVM());
        AddControlNavigationItems("Setup", new SetupForm(), new SetupFormVM());

        //Use the property instead which creates the instance and triggers property change
        CurrentViewModel = (IControlItem)View_ViewModel[View_ViewModel.Keys.ElementAt(0)].ViewModel;
        CurrentView = View_ViewModel[View_ViewModel.Keys.ElementAt(0)].View;
    }

    public List<IControlItem> ControlItemsNamesList
    {
        get => NavigationList;
    }
    /// <summary>
    /// Provides a list of names for Navigation controls to the control item
    /// </summary>
    public Dictionary<string, LinkViewToViewModel> ApplicationViews
    {
        get
        {

            return View_ViewModel;
        }
        set
        {
            View_ViewModel = value;
        }
    }

    public ContentControl CurrentView
    {
        get
        {
            return currentView;
        }
        set
        {
            currentView = value;
            OnPropertyChanged("CurrentView");
        }
    }
    public IControlItem CurrentViewModel
    {
        get
        {
            return currentNavigationItem;
        }
        set
        {
            if (currentNavigationItem != value)
            {
                currentNavigationItem = value;
                OnPropertyChanged("CurrentViewModel");
            }
        }
    }
    /// <summary>
    /// This property is bound to Button Command in XAML.
    /// Calls ChangeViewModel which sets the CurrentViewModel
    /// </summary>
    public ICommand ChangeViewCommand
    {
        get
        {
            if (changeViewCommand == null)
            {
                changeViewCommand = new ButtonClick(
                    p => ViewChange((IControlItem)p), CanExecute);
            }
            return changeViewCommand;
        }
    }

    #region Methods

    private MyNameSpace void ViewChange(IControlItem viewname)
    {
        foreach (KeyValuePair<string, LinkViewToViewModel> item in View_ViewModel)
        {
            if (item.Key == viewname.ControlName)
            {//Set the properties of View and ViewModel so they fire PropertyChange event
                CurrentViewModel = (IControlItem)item.Value.ViewModel;
                CurrentView = item.Value.View;
                break;
            }
        }

    }
    private MyNameSpace bool CanExecute()
    {
        return true;
    }
    #endregion
  }
}

其他课程

public class LinkViewToViewModel
{
    public LinkViewToViewModel(ContentControl view, ObservableObject viewModel)
    {
        View = view;
        ViewModel = viewModel;
    }
    public ContentControl View { get; set; }
    public ObservableObject ViewModel { get; set; }
}
© www.soinside.com 2019 - 2024. All rights reserved.