【问题标题】:binding View from VM variable从 VM 变量绑定视图
【发布时间】:2022-01-15 17:09:02
【问题描述】:

我想将来自 VM 内的 TelemetryDataPoint 的数据显示到视图中,只是为了提供更多信息,TelemetryDataPoint 从我的 Helper 类接收数据。我已经尝试过使用下面的代码,但不知何故,数据不会显示在我的视图中,但如果我调试TelemetryDataPoint,它就会有值。

TelemetryDataPointVM.cs

public class TelemetryDataPointVM : INotifyPropertyChanged
{       
    private TelemetryDataPoint? telemetryDataPoint;
   
    public TelemetryDataPoint? TelemetryDataPoint
    {
        get => telemetryDataPoint;
        set
        {
            // when I checked the value below it has the value
            telemetryDataPoint = value;
            OnPropertyChanged(nameof(TelemetryDataPoint));
        }
    }
    public TelemetryDataPointVM()
    {
        
    }
    public event PropertyChangedEventHandler? PropertyChanged;
    private void OnPropertyChanged(string propertyName) 
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

HelperClass.cs

public class GetPortHelper
    { 
        TelemetryDataPointVM TelemetryDataPointVM { get; set; }

        public GetPortHelper()
        {
            TelemetryDataPointVM = new();
        }

        private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
        {
            SerialPort sp = (SerialPort)sender;

            if(sp.IsOpen)
            {
                string DataString = sp.ReadLine();
                string[] arrayDataString = DataString.Split(",");

                if(arrayDataString[3] == "C")
                {
                   TelemetryDataPointVM.TelemetryDataPoint = ParseToTelemetryData(arrayDataString);
                }
                else if(arrayDataString[3] == "Y")
                {
                    //ParseToTetheredData(arrayDataString);
                }
             }
         }

    }

Altitude.xaml

<UserControl x:Class="GUI_Cansat.View.Altitude"
        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" 
        xmlns:local="clr-namespace:GUI_Cansat.View"
        xmlns:vm="clr-namespace:GUI_Cansat.ViewModel"
        mc:Ignorable="d" 
        d:DesignHeight="450" d:DesignWidth="800">
<UserControl.DataContext>
    <vm:TelemetryDataPointVM/>
</UserControl.DataContext>
<Grid>
    <Label  Content="{Binding TelemetryDataPoint.Altitude, Mode=TwoWay}"
            ContentStringFormat="Altitude:      {0} M"
            Style="{StaticResource fontMain}"
            VerticalAlignment="Center" FontSize="14"/>
</Grid>

更新 1:

我将我的Altitude 组装到我的MainWindows 中,如下所示:

<Border Style="{StaticResource borderMain}"
                Grid.Row="8">
            <view:Altitude  x:Name="Altitude" />
        </Border>

我应该把DataContext 放在这个&lt;view:Altitude/&gt; 里面吗?如果我把这样的代码和{Binding TelemetryDataPointVM} 放在一起,我的 VS 会告诉我“找不到用于绑定的数据上下文”

【问题讨论】:

  • 使用 Visual Studio 中的“XAML 绑定错误”窗口。你在里面看到什么? (在 VS 2019 v16.7 中添加,见这里:devblogs.microsoft.com/visualstudio/…
  • Protip:在 C# 中使用 this. 关键字,让阅读您的代码的人清楚识别标识符是否为实例成员。
  • 您的属性 set 逻辑应该只在属性值实际更改时调用 OnPropertyChanged,现在您在调用 setter 时调用它:这是不正确的,并且可能导致无限-循环(例如,如果一个 setter 链接到另一个 setter)。
  • &lt;vm:TelemetryDataPointVM/&gt; GetPortHelper.TelemetryDataPointVM 属性中引用的实例不同。跨度>
  • 您好,感谢您的回复。我在选项下检查了XAML Binding Errors,但我看不到那个设置(目前我正在使用VS 2022)@Dai

标签: c# wpf


【解决方案1】:

这里的问题是你有两个视图模型类的实例,一个是由

<UserControl.DataContext>
    <vm:TelemetryDataPointVM/>
</UserControl.DataContext>

还有一个

TelemetryDataPointVM = new();

在 GetPortHelper 构造函数中。

与任何其他控件一样,UserControl 永远不应显式设置自己的 DataContext(因此拥有自己的“私有”视图模型)。相反,它应该从它所在的主视图继承 DataContext,例如一个主窗口。

从 UserControl 的 XAML 中删除 DataContext 分配,并将 GetPortHelper 实例分配给 MainWindow 的 DataContext,例如喜欢

private readonly GetPortHelper portHelper = new GetPortHelper();

public MainWindow()
{
    InitializeComponent();
    DataContext = portHelper;
}

现在您将在 MainWindow 的 XAML 中声明 UserControl,例如

<local:Altitude DataContext="{Binding TelemetryDataPointVM}" />

这样的典型控制用例 - 在特定视图模型上运行 - 将是类似 DataTemplate 的

<DataTemplate DataType="{x:Type vm:TelemetryDataPointVM}">
    <local:Altitude />
</DataTemplate>

DataContext 继承自 ContentControl 或 ContentPresenter,该 ContentControl 或 ContentPresenter 具有 TelemetryDataPointVM 实例作为其内容,并根据其 DataType 自动应用上述 DataTemplate,例如

<ContentControl Content="{Binding TelemetryDataPointVM}" />

但是,您可以通过使其独立于特定视图模型来改进您的控制。该控件将公开一组可绑定的属性,例如AltitudeValue 属性,然后您可以像这样使用它:

<local:Altitude AltitudeValue="{Binding TelemetryDataPointVM.Altitude}" />

为了实现这一点,必须将 AltitudeValue 属性声明为 dependency property,并且 UserControl 的 XAML 中的 UI 元素将通过如下所示的 RelativeSource 绑定与其绑定:

<TextBlock Text="{Binding AltitudeValue,
    RelativeSource={RelativeSource AncestorType=UserControl}}" />

【讨论】:

  • 谢谢@Clemens,我无法在我的主窗口中绑定TelemetryDataPointVM,即使我已经在MainWindow下启动了GetPortHelper
  • 不确定“无法绑定”到底是什么意思。调试应用程序时,Visual Studio 的输出窗口中是否有任何数据绑定错误消息?
  • 当我尝试绑定它时,intellisense 没有给我TelemetryDataPointVM 并且没有引用GetPortHelper 对象的选项
  • 除了 Intellisense 之外,在运行应用程序时了解绑定是否确实有效会很有趣。如果您按照答案中的说明进行操作,则应该可以解决您最初拥有两个视图模型对象的问题。
  • 你好,很抱歉迟到了回复这个评论,我只是想问一下这个代码&lt;local:Altitude DataContext="{Binding TelemetryDataPointVM}" /&gt;我用我的问题更新了我的帖子。请检查一下
猜你喜欢
  • 2015-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多