【问题标题】:Wpf Databinding with ViewModel as property以 ViewModel 作为属性的 Wpf 数据绑定
【发布时间】:2018-07-25 07:00:36
【问题描述】:

为了保持我的 MainWindow.xaml.cs 干净,我尝试将所有内容外包给 ViewModel 类,然后将我的视图绑定到我的 ViewModel 属性的属性
然而,使用这个额外的层似乎不起作用。我的列表和文本框保持空白。有什么方法可以让这个方法起作用吗?

MainWindow 类:

public partial class MainWindow : Window, INotifyPropertyChanged
{
    public ViewModel ViewModel { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        ViewModel = new ViewModel();
    }
}

ViewModel 类:

public class ViewModel : INotifyPropertyChanged
{
    private string m_oneLineOnly;

    private ObservableCollection<string> m_sampleLines;

    public ObservableCollection<string> SampleLines
    {
        get => m_sampleLines;
        set
        {
            m_sampleLines = value;
            RaisePropertyChanged(nameof(SampleLines));
        }
    }

    public string OneLineOnly
    {
        get => m_oneLineOnly;

        set
        {
            m_oneLineOnly = value;
            RaisePropertyChanged(nameof(OneLineOnly));
        }
    }

    public ViewModel()
    {
        SampleLines = new ObservableCollection<string>(new List<string>()
        {
            "Gedanken",
            "Zeit",
            "Sand"
        });

        OneLineOnly = "Hello World";
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    private void RaisePropertyChanged(string propertyName)
    {
        var handlers = PropertyChanged;

        handlers(this, new PropertyChangedEventArgs(propertyName));
    }
}

主窗口 XAML

<Window x:Class="DataContext_Test_Project.MainWindow"
    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:DataContext_Test_Project"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800"
    x:Name="Window">
<Grid>
    <ListBox 
        HorizontalAlignment="Left"
        Height="100"
        Margin="334,132,0,0"
        VerticalAlignment="Top"
        Width="100"
        ItemsSource="{Binding ElementName=Window, Path=ViewModel.SampleLines}"/>
    <TextBox
        HorizontalAlignment="Left" 
        Height="23"
        Margin="184,166,0,0" 
        TextWrapping="Wrap"
        VerticalAlignment="Top"
        Width="120"
        DataContext="{Binding ElementName=Window, Path=ViewModel}"
        Text="{Binding Path=OneLineOnly}"/>
</Grid>

【问题讨论】:

  • 您的输出窗口是否显示绑定错误?尝试使用此方法添加有关绑定的更多信息并查看它们解析到的位置:spin.atomicobject.com/2013/12/11/wpf-data-binding-debug
  • 只需在InitializeComponent(); 之前调用ViewModel = new ViewModel();,一切正常。

标签: c# wpf xaml mvvm data-binding


【解决方案1】:

你也可以在后面的代码中定义DataContext:

public partial class MainWindow : Window
{
    public ViewModel ViewModel { get; set; }

    public MainWindow()
    {
        InitializeComponent();

        ViewModel = new ViewModel();
        DataContext = ViewModel;
    }
}

并清理您的 XAML:

<Grid>
    <ListBox 
         HorizontalAlignment="Left"
         Height="100"
         Margin="334,132,0,0"
         VerticalAlignment="Top"
         Width="100"
         ItemsSource="{Binding SampleLines}"/>
    <TextBox
         HorizontalAlignment="Left" 
         Height="23"
         Margin="184,166,0,0" 
         TextWrapping="Wrap"
         VerticalAlignment="Top"
         Width="120"
         Text="{Binding OneLineOnly}"/>
</Grid>

【讨论】:

  • 是否仍然可以使用此解决方案为各个文本框分配不同的数据上下文?
  • 是的。在子 Controls(无论他们的级别)上定义 DataContext 将覆盖全局。
  • 我喜欢在 XAML 中执行此操作,以便获得 Intelisense:(在 Window 标记中)DataContext="{Binding RelativeSource={RelativeSource Self}, Path=ViewModel}"
  • @KrzysztofSkowronek 如果您只想要智能感知,您可以使用“设计器”绑定,这样它就不会在运行时应用。 d:DataContext="{d:DesignInstance local:MyViewModelType}".
【解决方案2】:

为了让Bindings喜欢

ItemsSource="{Binding ElementName=Window, Path=ViewModel.SampleLines}"
DataContext="{Binding ElementName=Window, Path=ViewModel}"

工作,你有两个选择。要么让 ViewModel 属性触发属性更改通知,要么在解析 XAML 之前(即在调用 InitializeComponent() 之前)简单地初始化它:

像这样:

public partial class MainWindow : Window
{
    public ViewModel ViewModel { get; }

    public MainWindow()
    {     
        ViewModel = new ViewModel();
        InitializeComponent();
    }
}

或者更简单:

public partial class MainWindow : Window
{
    public ViewModel ViewModel { get; } = new ViewModel();

    public MainWindow()
    {     
        InitializeComponent();
    }
}

【讨论】:

    【解决方案3】:

    从 xaml.cs 文件中删除以下行:ViewModel = new ViewModel(); 对 Xaml 文件使用以下代码:

    <Window x:Class="DataContext_Test_Project.MainWindow"
                        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:DataContext_Test_Project"
                        mc:Ignorable="d"
                        Title="MainWindow" Height="450" Width="800"
                        x:Name="Window" DataContext="{DynamicResource ViewModel}">
         <Window.Resources>
                <local:ViewModel x:Key="ViewModel"/>
                </Window.Resources>
                    <Grid>
                        <ListBox 
                            HorizontalAlignment="Left"
                            Height="100"
                            Margin="334,132,0,0"
                            VerticalAlignment="Top"
                            Width="100"
                            ItemsSource="{Binding Path=SampleLines}"/>
                        <TextBox
                            HorizontalAlignment="Left" 
                            Height="23"
                            Margin="184,166,0,0" 
                            TextWrapping="Wrap"
                            VerticalAlignment="Top"
                            Width="120"
                            Text="{Binding Path=OneLineOnly}"/>
                    </Grid>
            </Window>
    

    【讨论】:

    • 这行得通。但是是否可以将对象创建保留在代码中?
    • 是的,您可以将视图模型对象保留在代码中并在那里设置数据上下文。但如果您使用的是 MVVM 模式,则不建议这样做。还要记住在 xaml 文件或代码中定义数据上下文
    猜你喜欢
    • 2011-02-01
    • 2011-02-04
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2015-11-24
    • 2016-01-11
    • 1970-01-01
    相关资源
    最近更新 更多