【问题标题】:How to bind usercontrols in xaml?如何在 xaml 中绑定用户控件?
【发布时间】:2012-02-27 22:52:42
【问题描述】:

我的 MainWindow 包含一个数据网格和一个“过滤器面板”。过滤器面板可以通过用户输入(按钮单击)进行更改。我尝试通过数据绑定来实现它。我面临的问题是过滤器面板(这是一个用户控件)没有加载或刷新。

主窗口 xaml:

 <Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="250*" />
        <ColumnDefinition Width="253*" />
    </Grid.ColumnDefinitions>
    <DataGrid AutoGenerateColumns="True" Height="200" HorizontalAlignment="Left" Margin="23,28,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="200" ItemsSource="{Binding OverviewableItems}" /> 
    <UserControl Grid.Column="1" Content="{Binding UserControl}" DataContext="{Binding}" Grid.ColumnSpan="2" />

    <Button Content="PersonFilter" Height="23" HorizontalAlignment="Left" Margin="23,268,0,0" Name="buttonPersonFilter" VerticalAlignment="Top" Width="75" Click="buttonPersonFilter_Click" />
    <Button Content="ProjectFilter" Height="23" HorizontalAlignment="Left" Margin="132,268,0,0" Name="buttonProjectFilter" VerticalAlignment="Top" Width="75" Click="buttonProjectFilter_Click" />

</Grid>

后面的代码:

 private ViewModel _viewModel;
    public MainWindow()
    {
        _viewModel = new ViewModel(new DataProvider());
        DataContext = _viewModel;
        _viewModel.PropertyChanged += _viewModel.SetFilterType;
        InitializeComponent();
    }


    private void buttonProjectFilter_Click(object sender, RoutedEventArgs e)
    {
        _viewModel.OverviewType = OverviewType.Project;
    }

    private void buttonPersonFilter_Click(object sender, RoutedEventArgs e)
    {
        _viewModel.OverviewType = OverviewType.Person;
    }

第一个用户控件:

<Grid>
    <DatePicker Grid.Column="1" Grid.Row="1" Height="25" HorizontalAlignment="Left" Margin="19,18,0,0" Name="datePickerFundingTo" VerticalAlignment="Top" Width="115" Text="{Binding ElementName=ProjectFilter, Path=FundingTo}" />
</Grid>

此用户控件的代码如下:

 public DateTime FundingTo { get; set; }
 public ProjectFilter()
    {
        FundingTo = DateTime.Now;

        InitializeComponent();
    }

其他用户控件:只包含一个TextBox和一个Button,为简单起见,我没有在后面添加任何代码。

主窗口的ViewModel:

public class ViewModel  : INotifyPropertyChanged
{
    private UserControl _userControl;

    public UserControl UserControl
    {
        get { return _userControl; }
        set
        {
            if (_userControl == value)
            {
                return;
            }
            OnPropertyChanged("UserControl");
            _userControl = value;
        }
    }

    private OverviewType _overviewType = OverviewType.None;
    public OverviewType OverviewType
    {
        get { return _overviewType; }
        set
        {
            if (_overviewType == value)
            {
                return;
            }
            OnPropertyChanged("OverviewType");
            _overviewType = value;
        }
    }

    private ObservableCollection<IOverviewItem> _overviewableItems;
    public ObservableCollection<IOverviewItem> OverviewableItems
    {
        get { return _overviewableItems; }
        set
        {
            if (_overviewableItems == value)
            {
                return;
            }
            _overviewableItems = value;
        }
    }

    private readonly DataProvider _dataProvider;

    public event PropertyChangedEventHandler  PropertyChanged;

    public ViewModel(DataProvider dataProvider)
    {
        _dataProvider = dataProvider;
    }

    public void SetFilterType(object sender, EventArgs eventArgs)
    {

        switch (_overviewType)
        {
            case OverviewType.Project:
                _userControl = new ProjectFilter();
                break;
            case OverviewType.Person:
                _userControl = new PersonFilter();
                break;
        }
    }

    public void OnPropertyChanged(string name)
    {
        if (PropertyChanged == null)
            return;

        var eventArgs = new PropertyChangedEventArgs(name);
        PropertyChanged(this, eventArgs);
    }  
}

另外我有一个枚举 OverviewType,其中包含 None、Project、Person 值。

正确触发了属性更改事件,但未刷新用户控件。谁能启发我,我的解决方案的缺陷在哪里?

还有一个问题,我如何从用户控件与主窗口视图模型进行通信?外汇:数据网格应根据其过滤器进行更改。

任何帮助将不胜感激。干杯!

【问题讨论】:

    标签: c# wpf xaml data-binding user-controls


    【解决方案1】:

    这里有不同的问题。

    • 正如 Clemens 所说,您必须在值更新后触发您的事件。但这不是这里的主要问题。

    • 第二个问题:你正在影响你的新usercontrol 私人成员,所以你完全绕过了你的财产。

    替换

    _userControl = new ProjectFilter();
    

    通过

    this.UserControl = new ProjectFilter();
    
    • 第三个问题,与您的问题没有直接关系,但实际上是您的最大问题:您有一个架构设计问题。你在你的视图模型中暴露了一个UserControl,它是一个anti-pattern。您的视图模型必须不知道关于视图的任何信息,因此它不得对视图内的控件有任何引用。除了您编写的绑定之外,您还可以从视图模型中触发一个事件并在您的视图中添加一个事件处理程序,以便 您的视图 更新用户控件。

    【讨论】:

    • 我明白你的意思。但是可以使用绑定选项吗?或者最好像这样添加它? stackPanelFilter.Children.Clear(); stackPanelFilter.Children.Add(UserControl); - 查看后面的代码
    • @JahManCan 绑定选项可以工作,但它真的不是 MVVM 模式。第二个选项比 IMO 好得多(对于纯粹与视图相关的事情,后面的视图代码是可以的)。
    【解决方案2】:

    更改属性的支持字段后尝试触发 PropertyChanged:

    public UserControl UserControl
    {
         get { return _userControl; }
         set
         {
             if (_userControl != value) 
             {
                _userControl = value;              // first
                 OnPropertyChanged("UserControl"); // second
             }
         } 
    }
    

    OverviewType 类似。

    【讨论】:

    • 你说得对,但这并不能解决我面临的问题。我会研究一下Ken2k的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2016-01-12
    • 1970-01-01
    • 2012-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 2010-11-18
    相关资源
    最近更新 更多