WPF数据绑定到Window DataContext对象属性

时间:2014-10-14 19:56:12

标签: c# wpf xaml wpfdatagrid

** [解决] **这是我在这里提出的第一个问题,所以有些错误可以通过。 在我的WPF应用程序中,我想以“双向模式”将所有控件绑定到特殊对象实例BuildingManagementSystem中的相应属性,我想将其设置为Window DataContext。 但没有任何作用(数据不显示)。绑定它的正确方法是什么?

这是我的代码:

public partial class MainWindow : Window
{

    BuildingManagementSystem bms { get; set; }

    public MainWindow()
    {    
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(Window1_Loaded);
    }

    void Window1_Loaded(object sender, RoutedEventArgs e)
    {
        bms = new BuildingManagementSystem();
        this.DataContext = bms;         
}

public class BuildingManagementSystem
{
    public string Name { get; set; }

    public readonly FireAlarmSystem FireAlarmSystem;

    public BuildingManagementSystem()
    {          
        FireAlarmSystem = new FireAlarmSystem();         
    }
}

class FireAlarmSystem
{

    private int alarmSmokeRate, currentSmokeRate;

    public  List<PowerConsumer> Devices { get; set; }

    public int CurrentSmokeRate
    {
        get { return currentSmokeRate; }
        set { SetField(ref currentSmokeRate, value, () => CurrentSmokeRate); }
    }


    public FireAlarmSystem()
    {
        Devices = new List<PowerConsumer>();

    }
}

class PowerConsumer
{
    public string Name { get; set; }
    public double Power { get; set; }
    public int Priority { get; set; }
    public bool Enabled { get; set; }
}

XAML:

<DataGrid Name="FireAlarmGrid" HorizontalAlignment="Left" Margin="10,51,0,0" CanUserAddRows="True" 
            CanUserDeleteRows="True" VerticalAlignment="Top" AutoGenerateColumns="False" ItemsSource="{Binding  FireAlarmSystem.Devices}"  >

    <DataGrid.RowValidationRules>

        <local:FireValidationRule ValidationStep="UpdatedValue"/>

    </DataGrid.RowValidationRules>

    <DataGrid.Columns>
        <DataGridCheckBoxColumn Header="Enabled" Binding="{Binding Enabled}"></DataGridCheckBoxColumn>
        <DataGridTextColumn Header="Name" Binding="{Binding Name,ValidatesOnExceptions=True }" >

        </DataGridTextColumn>
        <DataGridTextColumn Header="Power" Binding="{Binding Power}"></DataGridTextColumn>

    </DataGrid.Columns>

</DataGrid>



<TextBox Name="tbCurrentSmokeRate"   Text="{Binding Path=FireAlarmSystem.CurrentSmokeRate, Mode=TwoWay}" VerticalAlignment="Top" Width="70"/>  

4 个答案:

答案 0 :(得分:1)

我个人喜欢创建viewmodel的静态实例,如下所示:

<Window.Resources>
    <ViewModels:MainWindowVM x:Key="VM"></ViewModels:MainWindowVM>

当我这样做时,绑定很容易,因为专业页面在VS中找到了你的属性。

 <StackPanel Grid.Column="0" Margin="5,5,5,0"  
          DataContext="{Binding Source={StaticResource VM}}">

但请记住,您需要添加命名空间

 xmlns:ViewModels="clr-namespace:MyWPF.ViewModels" 
 xmlns:Views="clr-namespace:MyWPF.Views" 

这允许属性绑定如下:

    <Views:UcTitle x:Name="XTitle" ></Views:UcTitle>
    <Views:UcLegendTitle x:Name="XLegendTitle"/>
    <Views:UcSeriesTitle x:Name="XSeriesTitle" />
    <Views:UcSeriesTypes x:Name="XSeriesTypes"/>

而且您不必在...中键入任何名称 在您的情况下,您没有使用ViewModel,但您正在正确设置数据上下文。所以这只能是没有要显示的数据或不正确的属性绑定。记住这个工作你需要三件事1)DataContext 2)Vales和3)按名称正确绑定...这是第三个在刚刚开始使用伟大的WPF绑定系统时惹恼了很多人。

答案 1 :(得分:0)

让MVVM正常工作......

您需要更新View Model以实现INotifyPropertyChanged,让wpf知道您的属性已更改

使用Observable集合而不是列表,ObservableCollections具有让Datagrid listview,列表框知道集合中的项目已更改的连线

将字段更改为属性,以便WPF可以看到它......

<DataGrid Name="FireAlarmGrid" HorizontalAlignment="Left" Margin="10,51,0,0" CanUserAddRows="True" 
                          CanUserDeleteRows="True" VerticalAlignment="Top" AutoGenerateColumns="False" ItemsSource="{Binding  FireAlarmSystem.Devices}"  >

        <DataGrid.RowValidationRules>

            <local:FireValidationRule ValidationStep="UpdatedValue"/>

        </DataGrid.RowValidationRules>

        <DataGrid.Columns>
            <DataGridCheckBoxColumn Header="Enabled" Binding="{Binding Enabled,Mode=TwoWay}"></DataGridCheckBoxColumn>
            <DataGridTextColumn Header="Name" Binding="{Binding Name,ValidatesOnExceptions=True,Mode=TwoWay }"  >

            </DataGridTextColumn>
            <DataGridTextColumn Header="Power" Binding="{Binding Power,Mode=TwoWay}"></DataGridTextColumn>

        </DataGrid.Columns>
    </DataGrid>

    <TextBox Name="tbCurrentSmokeRate"   Text="{Binding Path=FireAlarmSystem.CurrentSmokeRate, Mode=TwoWay}" VerticalAlignment="Top" Width="70"/>


public class BuildingManagementSystem : INotifyPropertyChanged
{
    private string _Name;

    public string Name
    {
        get { return _Name; }
        set
        {
            if (_Name != value)
            {
                _Name = value;
                PropertyChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }
    }

    private FireAlarmSystem _fireAlarmSystem;
    public FireAlarmSystem FireAlarmSystem { get { return _fireAlarmSystem; } }

    public BuildingManagementSystem()
    {
        _fireAlarmSystem = new FireAlarmSystem();
    }

    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    #endregion
}

public class FireAlarmSystem : INotifyPropertyChanged
{

    private int alarmSmokeRate, currentSmokeRate;

    public ObservableCollection<PowerConsumer> Devices { get; set; }


    public int CurrentSmokeRate
    {
        get { return currentSmokeRate; }
        set
        {

            //SetField(ref currentSmokeRate, value, () => CurrentSmokeRate);
            PropertyChanged(this, new PropertyChangedEventArgs("CurrentSmokeRate"));
        }
    }


    public FireAlarmSystem()
    {
        Devices = new ObservableCollection<PowerConsumer>();
        //Create some test data...
        Devices.Add(new PowerConsumer() { Name = "One", Enabled = true, Power = 100, Priority = 1 });
        Devices.Add(new PowerConsumer() { Name = "two", Enabled = false, Power = 101, Priority = 2 });
        Devices.Add(new PowerConsumer() { Name = "three", Enabled = false, Power = 103, Priority = 3 });
    }
    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    #endregion
}

public class PowerConsumer
{
    public string Name { get; set; }
    public double Power { get; set; }
    public int Priority { get; set; }
    public bool Enabled { get; set; }
}

答案 2 :(得分:0)

这里有几个错误

  1. 看起来像BuildingManagementSystem是您的数据上下文
  2. 取代BuildingManagementSystem bms {get;组;写下面的代码:

    BuildingManagementSystem bms = new BuildingManagementSystem();

    1. 您需要在ViewModel中实现INotifyPropertyChanged事件以反映UI上的更改
    2. 如果您打算为每个基础子视图模型分配值,请使用参数化构造函数来传递和赋值。简单地在父级中实例化子视图模型将不起任何作用。

答案 3 :(得分:0)

感谢所有人,我发现了一个错误,它将FireAlarmSystem定义为readonly,它被称为属性。 2 Stuart Smith,你是INotifyPropertyChanged的右边,但我有一个抽象的类 - 祖先BuildingSystem,它实现了这个接口。我忘记发帖了。