我仍然在为更好地表达问题而努力。这是我到目前为止有:绑定两个动态加载的xaml文件的两个UI元素
包含的模块列表,其中一些模块是通用模块
[Serializable]
class ModuleList
{
public ObservableCollection<Module> Items
{
get;
set;
}
public ModuleList()
{
Items = new ObservableCollection<Module>();
}
}
[Serializable]
class Module : INotifyPropertyChanged
{
private string name;
public string Name
{
get
{
return this.name;
}
set
{
if(this.name != value)
{
this.name = value;
this.NotifyPropertyChanged("Name");
}
}
}
[field: NonSerialized]
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if(this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
[Serializable]
class SpecializedModule : Module
{
public SpecializedModule()
{
mode = false;
}
private bool mode;
public bool Mode
{
get
{
return this.mode;
}
set
{
if(this.mode != value)
{
this.mode = value;
this.NotifyPropertyChanged("Mode");
}
}
}
}
的项目清单作为ItemSource
为ListView
的专门版本的自定义类。选择列表中的项目将使用XamlReader
加载相应的.xaml。 A System.Windows.Control.Grid
,被用作模块特定UI的容器。如预期由网格的数据上下文设置为模块列表
switch (it.ModID)
{
case "SOMEMODID":
loadGrid("somemodule.xaml");
break;
default:
loadGrid("_dummy.xaml");
break;
}
grpModCfg.DataContext = modListSel;
然后使用转换器
public class ModuleListToModuleConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is ModuleList)
{
ModuleList modList = value as ModuleList;
int idx = modList.getItemIndex(parameter as string);
if (idx != -1)
{
return modList.Items[idx];
}
else
{
return null;
}
}
else
{
return null;
}
}
public object ConvertBack(object obj, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
一个例子的子网格的DataContext
设定到相应的模块“正常”结合的作品。 xaml:
<Grid Name="grdSomeMod"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ModCfg;assembly=ModCfg"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="395"
d:DesignWidth="480" >
<Grid.Resources>
<local:ModuleListToModuleConverter x:Key="modlistConverter" />
</Grid.Resources>
<Grid.DataContext>
<Binding Converter="{StaticResource modlistConverter}" ConverterParameter="SOMEMODEID" />
</Grid.DataContext>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240*" />
<ColumnDefinition Width="240*" />
</Grid.ColumnDefinitions>
<CheckBox Content="Some Parameter" Height="16" HorizontalAlignment="Left" IsChecked="{Binding PropertyOfSomeModule}" Margin="6,6,0,0" VerticalAlignment="Top" Name="chkSomePar" />
</Grid>
这适用于绑定特定模块的属性。不过,我也有其他的模块,例如性能的依赖性,所以我需要像
- CheckBoxA.IsChecked = moduleA.SomeProperty
- CheckBoxB.IsEnabled = moduleB在列表& & moduleB.SomeOtherProperty ==真/假
我试了一下,到目前为止:
- 方法的一个
- 离开
DataContext
设置为我的模块列表,以便我可以访问所有这些 - 设置每个元素的情况下,让那些需要访问另一个模块具有上下文
- 问题:一旦我设定上下文到一个模块,我无法访问另一个模块,因此将
IsEnabled
绑定到moduleA的属性并将IsChecked
绑定到模块B的属性是不可能的。
- 离开
- 方法乙
- 使用的转换器瓦特/参数指定模块和哪个属性以搜索
- 问题(逗号分隔,然后在变换器分割):它适用于的IsEnabled,但器isChecked抱怨关于需要一个路径,因为双向绑定,我似乎无法找到一个工程。
XAML的方法答:
<Grid Name="grdSomeMod"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ModCfg;assembly=ModCfg"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="395"
d:DesignWidth="480" >
<Grid.Resources>
<local:ModuleListToModuleConverter x:Key="modlistConverter" />
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240*" />
<ColumnDefinition Width="240*" />
</Grid.ColumnDefinitions>
<CheckBox Content="Some Parameter" Height="16" HorizontalAlignment="Left" IsChecked="{Binding PropertyOfSomeModule}" Margin="6,6,0,0" VerticalAlignment="Top" Name="chkSomePar>
<CheckBox.DataContext>
<Binding Converter="{StaticResource modlistConverter}" ConverterParameter="SOMEMODEID" />
</Checkbox.DataContext>
</CheckBox>
</Grid>
XAML的方法B:
<Grid Name="grdSomeMod"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ModCfg;assembly=ModCfg"
mc:Ignorable="d"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
d:DesignHeight="395"
d:DesignWidth="480" >
<Grid.Resources>
<local:ModuleListToModuleConverter x:Key="modlistConverter" />
<local:ModuleListToModuleDefineConverter x:Key="defBinaryConverter" />
</Grid.Resources>
<Grid.DataContext>
<Binding Converter="{StaticResource modlistConverter}" ConverterParameter="SOMEMODEID" />
</Grid.DataContext>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="240*" />
<ColumnDefinition Width="240*" />
</Grid.ColumnDefinitions>
<CheckBox Content="Some Parameter" Height="16" HorizontalAlignment="Left" IsChecked="{Binding PropertyOfSomeModule}" Margin="6,6,0,0" VerticalAlignment="Top" Name="chkSomePar">
<CheckBox.IsChecked>
<!--not working atm-->
<Binding Path="." Converter="{StaticResource defBinaryConverter}" ConverterParameter="SOMEMODID,SomeProperty" />
</CheckBox.IsChecked>
<CheckBox.IsEnabled>
<Binding Converter="{StaticResource defBinaryConverter}" ConverterParameter="SOMEOTHERMODID,SomeOtherProperty" />
</CheckBox.IsEnabled>
</CheckBox>
</Grid>
而对于B方法的转换器:
public class ModuleListToModuleDefineConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (value is ModuleList)
{
ModuleList modlist = value as ModuleList;
string paramList = parameter as string;
string[] pars = paramList.Split(',');
int idx = modlist.getItemIndex(pars[0]);
if (idx != -1)
{
switch (pars[0])
{
case "SOMEMODID":
switch (pars[1])
{
case "SomeProperty":
return (modlist.Items[idx] as SomeModule).C0x10;
}
break;
case "SOMEOTHERMODID":
switch (pars[1])
{
case "SomeOtherProperty":
return (modlist.Items[idx] as SomeOtherMod).SomeOtherProperty;
}
break;
}
}
return false;
}
else
{
return false;
}
}
public object ConvertBack(object obj, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
这是一个相当批量的代码,但这也是我一直试图解决大约一周的问题,而且我觉得我正在变得非常接近,但是可能会忽略某些东西。
也许有一个更优雅的方式来做到这一点?
我觉得这个问题不清楚。例如。为什么要动态加载XAML?为什么不根据需要将适当的模板作为参考资源?为什么数据上下文不仅仅是模板加载/引用的模块实例?上面有一个很大的代码转储,但它不完整,同时包含了对于这个问题看起来并不是必须的东西。请阅读[mcve]了解如何提供一个很好的代码示例。请具体说明代码的作用,以及与您想要的不同之处。 –
@PeterDuniho我应该可能已经说过我对WPF来说也是一个新手,所以我的问题可能仅仅是因为我对这个问题缺乏了解。动态加载XAML似乎是没有一个巨大的XAML与其中的所有模块的最佳方式。我没有看到如何从资源加载页面与加载文件不同。如果每个模块的数据上下文从一开始就被设置为模块,就无法访问另一个模块的属性来映射依赖关系,据我所知 - 这是我的问题。 – Soukyuu
_“我没有看到如何从资源中加载页面与在我的情况下加载文件不同”_ - 如果您已将模板定义为资源,那么您可以利用WPF中的现有模板功能,而不是必须编写代码隐藏来匹配具有数据类型的模板。至于其他问题,不幸的是,您的问题并未明确“访问另一个模块的属性来映射依赖关系”的含义。模板只需要访问它定义的模块类型的属性。 –