绑定到WPF中的另一个绑定
本文关键字:绑定 另一个 WPF | 更新日期: 2023-09-27 18:16:27
在一个简单的MVVM应用程序中,我可以向视图中的某些属性添加绑定。属性可以访问另一个对象并从中返回属性值。假设我想在视图中显示活动项目。如果没有项目处于活动状态,将显示一个特殊的注释。
现在,当重命名项目时,视图中的名称应该更新。如果我只是在属性中返回项目的名称,它当然不会被更新。
所以我认为我可以将视图绑定到属性中创建的另一个绑定,它应该转发PropertyChanged事件并相应地更新视图。但我看到的是"System.Windows.Data"。而不是预期的绑定结果,如"Project: XYZ"。
该项目可以在任何地方重命名,所以我想避免从那里自己为这个ViewModel引发PropertyChanged事件。事情本身应该更聪明一点,而不需要从任何地方推来推去(当事情变得更复杂时,你经常至少忘记一次)。
代码如下:
XAML视图:<TextBlock Text="{Binding ActiveProjectName}"/>
c# ViewModel: public object ActiveProjectName
{
get
{
if (ActiveProject != null)
{
// This works but won't update automatically:
//return "Project: " + ActiveProject.Name;
// This does not work at all:
return new Binding("Name")
{
Source = ActiveProject,
StringFormat = "Project: {0}"
};
}
return "(No active project)";
}
}
这是可能的吗?它是如何工作的?
除非ActiveProject属性是私有或受保护的,否则在xaml中使用FallbackValue而不是
后面代码中的if(ActiveProject != null)
。例子<TextBlock Text="{Binding ActiveProject.Name,StringFormat=Project: {0},FallbackValue=(No active project)}"/>
使用PriorityBinding
具有条件绑定
<TextBlock>
<TextBlock.Text>
<PriorityBinding FallbackValue="(No active project)">
<Binding Path="ActiveProject.Name"
StringFormat="Project: {0}"/>
<Binding Path="SomeOtherProject.Name"
StringFormat="Other Project: {0}" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
在上面的示例中PriorityBinding将首先尝试绑定到ActiveProject,然后使用Name属性来解析值。如果这是不可用的ie。null,那么它将尝试绑定到SomeOtherProject。为了根据绑定解析值,如果结果也是null,那么FallbackValue将被用作TextBlock的Text属性的值。
不不不不!; D
使用IValueConverter !http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter (v = vs.110) . aspx
通常我会保留一个ActiveProject/ActiveWhatever属性,我将在代码的某个地方设置,而不是创建越来越疯狂的绑定,使你的标记和代码变得复杂。
还要确保在所有实体上实现INotifyPropertyChanged,这里你只有一个getter。在代码中设置绑定是你应该避免的事情!(DO vm's和DP's在其中是最重要的)。
数据模型/实体:
public class ActiveProject : INotifyPropertyChanged
{
private string name;
public String Name
{
get { return name; }
set
{
if (value == name) return;
name = value;
OnPropertyChanged(); // Signals the UI that the property value has changed, and forces a re-evaluation of all bindings for this property
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator] // No R#? Shame on you and comment this line out
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
转换器:
public class YourConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
// Do whatever you want here
ActiveProject project = value as ActiveProject;
return project == null ? project.Name : "Whatever";
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
// Convert back if needed
throw new NotImplementedException();
}
}
XAML: ...
<xx.Resources>
<local:YourConverter x:Key="YourConverter"/> <!--Define your converter as a staticresource, given that local is the namespace you have define. Alt+Enter with R# -->
<xx.Resources>
...
<TextBlock Text="{Binding ActiveProject, Converter={StaticResource local:YourConverter}}"/>