C# WPF 我不能私下更新,但公众会
Posted
技术标签:
【中文标题】C# WPF 我不能私下更新,但公众会【英文标题】:C# WPF I cannot get private to update but public will 【发布时间】:2022-01-17 15:05:20 【问题描述】:我对此感到非常困惑并且已经搜索但找不到答案。我确定我没有正确理解某些内容。你能给我解释一下吗?
我有一个视图和一个视图模型。在视图中我有一个文本块
<TextBlock
Grid.Row="4"
Grid.Column="5"
Grid.ColumnSpan="3"
IsEnabled="Binding Enable, Mode=OneWay"
Margin="5,10,5,10">
<Run Text="File: "/>
<Run Text="Binding FilePathName"/>
</TextBlock>
在我拥有的视图的顶部
d:DataContext="d:DesignInstance d:Type=viewModels:MainWindowViewModel"
我还在后面的代码中添加了
public MainWindow()
InitializeComponent();
DataContext = new MainWindowViewModel();
我不想在此处添加 DataContext,但一开始似乎可以让它工作,但现在我不确定我是否需要它,我会尝试删除它。
我想我理解这部分,View 中的数据将从 ViewModel 中名为 FilePathName 的项刷新。
现在在视图模型中,我为 FilePathName 创建了“获取和设置”:
private string _filepathname;
public string FilePathName
get => _filepathname;
set
if (_filepathname != value)
_filepathname = value;
OnPropertyChanged();
现在这就是我的理解有点模糊的地方。我认为在 ModelView 中我将只使用私有字符串。这意味着当我像这样更改它的值时:
_filepathname = “MyNewName”;
然后 PropertyChanged 将看到此更改并通过公共 FilePathName 更新视图。但是,如果我使用 FileOpenDialog 并打开一个文件,然后说
if (openFileDialog.FileName != "")
_filepathname = openFileDialog.FileName;
ProcessFile();
我在这里使用私人,但这永远不会更新。如果我在“get and set”中设置断点,我们永远不会去那里,所以 UI 永远不会更新。
但是我在 ProcessFile() 中使用
StreamReader sr = new StreamReader(_filepathname);
我确实阅读了正确的文件。这我可以理解,因为它也是私人的。但是……如果我现在将私有更改为公开,如下所示
if (openFileDialog.FileName != "")
FilePathName = openFileDialog.FileName;
ProcessFile();
我现在更新 UI 并打开正确的文件进行阅读。似乎有时我需要使用私有的,有时是公共的才能使其工作。为什么?
第二个问题是为什么 isEnabled 似乎不适用于 TextBlock。我让它在按钮和文本框上工作。我在TextBlock中使用它如下,你可以在上面看到它。
IsEnabled="Binding Enable, Mode=OneWay"
感谢所有帮助。
【问题讨论】:
“IsEnabled 似乎不适用于 TextBlock”是什么意思? 如果 IsEnabled 为真,我希望看到文本,但如果为假,我不希望看到文本。 Using Properties (C# Programming Guide). 【参考方案1】:这样不行。 如果是,我们为什么需要属性?
这个:
myString = "new value"
仅将值分配给变量。就这样。当您使用属性执行此操作时,将调用属性设置器,因此:
if(myString != value)
myString = value; //new value will be assigned to variable
OnPropertyChanged(); //property changed will be called
当您将值分配给变量时,您只需读取它就可以了。 此变量称为“支持字段”。它在那里是因为必须有一些变量来存储一个值。如果你这样声明属性:
public string MyString get; set;
在底层,编译器也创建了这样的支持字段,最终它的工作方式如下:
string __myString;
public string MyString
get return __myString;
set __myString = value;
所以,如您所见,这只是一种合成糖。如果你想从属性中获得更多(比如调用属性改变),你必须自己创建这样的 bakcing 字段。
更重要的是,属性本身不存储任何值。把它想象成一种方法。实际上有两种方法 - 一种为变量赋值,另一种返回值:
public void SetMyString(string value)
myString = value;
public string GetMyString()
return myString;
因为属性也是某种合成糖。
总结一下:
string myString;
public string MyString
get return myString;
set
if(myString != value)
myString = value;
OnPropertyChanged();
///
myString = "NewValue"; //<-- only assigns value to variable myString
MyString = "NewValue"; //<-- assings value to variable myString AND calls OnPropertyChanged - because that's how you property setter looks like.
【讨论】:
常用术语是“backing field”。 你说得对,我会更新的。 非常感谢,这是我见过的最好的解释,对我来说也很完美。它帮助我理解其他人告诉我的魔力。非常感谢您花时间解释它。【参考方案2】:您的视图和视图模型是两个不同的类。
当您更改视图模型的私有字段时,您的视图无法知道它是否没有收到通知。当您在属性设置器中调用 OnPropertyChanged()
时,您会通知视图。修改字段时不会调用属性设置器。阅读Adam's anwser了解更多详情。
要回答您的第二个问题,IsEnabled
不是您要查找的属性,因为它会禁用 UI 元素,但不会隐藏它。您需要为此更改 Visibility 属性(使用转换器)。
我会这样做(还有其他简化):
<!-- in application or control resources -->
<BooleanToVisibilityConverter x:Key="BooleanToVisibility" />
<TextBlock Grid.Row="4"
Grid.Column="5"
Grid.ColumnSpan="3"
Text="Binding FilePathName, StringFormat=File: 0"
Visibility="Binding Enable, Mode=OneWay, Converter=StaticResource BooleanToVisibility"
Margin="5,10"/>
【讨论】:
感谢您向我解释这一点。我认为我需要研究转换器的整个主题,因为它们看起来非常有用。以上是关于C# WPF 我不能私下更新,但公众会的主要内容,如果未能解决你的问题,请参考以下文章