管理和绑定用户控件

时间:2014-04-07 12:10:04

标签: c# wpf mvvm user-controls

我是WPF的新手,现在我遇到的情况是我无法找到任何有效的解决方案。 在我的项目中,我有很多viewmodels和usercontrols。主窗口分为两个,在左侧,我根据当前的视图模型显示用户控件,每个工作正常。当我想根据左侧选择的用户在右侧显示第二个用户控件时,问题就开始了。用户控件有许多文本框和组合框。我将如何从cosequtive视图模型中绑定这些数据?

//mainwindow.xaml
<Window.resources>
<Datatemplate Datatype={x:Type vm:Viewmodel1}>
<loc:Usercontrol1/> // in the left hand side
</DataTemplate>
<Datatemplate Datatype={x:Type vm:Viewmodel2}>
<loc:Usercontrol2/> // in the lefthand side
</DataTemplate>
</Window.Resources>
...
<Grid Grid.Column="0">
<ContentControl Content={Binding CurrentViewModel}/>
</Grid>
<Grid Grid.Column="1">
<Grid.Resources>
 <Datatemplate Datatype={x:Type vm:Viewmodel1}>
<loc:Usercontrol3 NameDp={Binding Name}/> // in the right hand side
</DataTemplate>
<Datatemplate Datatype={x:Type vm:Viewmodel2}>
<loc:Usercontrol3/> // in the rightthand side
</DataTemplate>
</Grid.Resources>
</Grid>

// Usercontrol3.xaml
<Grid>
<TextBox Text="{Binding Path=NameDp, ElementName=UserControl3}" />
</Grid> 
// UserControl3.cs
public static readonly DependencyProperty NameUCProperty  =DependencyProperty.Register("NameDp", typeof(string), typeof(UserControl3), new FrameworkPropertyMetadata(NamePropertyChanged));
public string NameDp
    {
        get
        {
            return (string)GetValue(NameUCProperty);
        }
        set
        {
            SetValue(NameUCProperty, value);
        }
    }

//ViewModel
Public Name {get;set;}

在每个视图模型中,我从数据库中获取数据,我想根据用户选择将这些数据绑定到右侧的Usercontrols。我如何绑定这些数据? 这是正确的approch还是我完全错了?

1 个答案:

答案 0 :(得分:1)

这绝对是一种方法。对我来说,我会用这种方式组织。我在这里有一个原型,演示了这些东西是如何工作的......

首先,我们的MainWindow

<Window x:Class="WpfUserControlsBindingListeningNotMuchHere.MainWindow"
        xmlns:t="clr-namespace:WpfUserControlsBindingListeningNotMuchHere"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:ms="clr-namespace:System;assembly=mscorlib"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Window.DataContext>
        <t:ViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <t:UserControl1 x:Name="uc1"
                        Items="{Binding Items}"
                        Selected="{Binding Selected, Mode=TwoWay}" />
        <t:UserControl2 Grid.Column="1"
                        DataContext="{Binding Result}" />
    </Grid>
</Window>

注意 uc1 。它接收一个列表并公开所选项目。这些都绑定到ViewModel。属性ItemsSelected是我在UserControl上定义的 DependencyProperties 。如果你愿意,我可以显示代码,但没有它应该是可以理解的。 (如果我调整了DP定义,Mode=TwoWay可以省去。)

在ViewModel中,我会听取Selected的更改,并相应地开展工作。

class ViewModel : INotifyPropertyChanged
{
    private object _selected;

    private object _result;

    public event PropertyChangedEventHandler PropertyChanged;

    public ObservableCollection<object> Items { get; private set; }

    public object Selected
    {
        get { return this._selected; }
        set
        {
            if (_selected == value)
                return;
            this._selected = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Selected"));
        }
    }

    public object Result
    {
        get { return this._result; }
        set
        {
            if (_result == value )
            return;
            this._result = value;
            PropertyChanged(this, new PropertyChangedEventArgs("Result"));
        }
    }

    public ViewModel()
    {
        Items = new ObservableCollection<object>();
        Items.Add(1);
        Items.Add("hello");
        Items.Add(3.0d);
        PropertyChanged += OnPropertyChanged;
    }

    private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if (e.PropertyName != "Selected")
            return; 

        //DO MASSIVE WORK HER ON BACKGROUND THREAD OR SOMETHING LOL
        Result = "OMG THIS TOOK A LONG TIME, " + Selected.ToString();
    }
}

所以,我只是在观察对Selected的更改,此时我会完成我的工作(业务逻辑)并在另一个属性中公开结果。然后将其绑定到UI中的第二个UserControl。

正如我所说,UC代码是微不足道的......

<UserControl x:Class="WpfUserControlsBindingListeningNotMuchHere.UserControl1"
             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" 
             x:Name="root">
    <ListBox ItemsSource="{Binding Items, ElementName=root}"
             SelectedItem="{Binding Selected, ElementName=root}" />
</UserControl>

和代码隐藏(OMG CODEBEHIND LOOK OUT EVIL)

public partial class UserControl1 : UserControl
{
    #region Items
    public static readonly DependencyProperty ItemsProperty =
    DependencyProperty.Register(
        "Items",
        typeof(IEnumerable<object>),
        typeof(UserControl1),
        new UIPropertyMetadata(null));

    public IEnumerable<object> Items
    {
        get { return (IEnumerable<object>)GetValue(ItemsProperty); }
        set { SetValue(ItemsProperty, value); }
    }
    #endregion

    #region Selected
    public static readonly DependencyProperty SelectedProperty =
    DependencyProperty.Register(
        "Selected",
        typeof(object),
        typeof(UserControl1),
        new UIPropertyMetadata(null));

    public object Selected
    {
        get { return (object)GetValue(SelectedProperty); }
        set { SetValue(SelectedProperty, value); }
    }
    #endregion

    public UserControl1()
    {
        InitializeComponent();
    }
}

<UserControl x:Class="WpfUserControlsBindingListeningNotMuchHere.UserControl2"
             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="300" d:DesignWidth="300">
    <TextBlock Text="{Binding}" />
</UserControl>

这个没有代码隐藏。