2015-09-06 72 views
0

我有一个来自客户端的有趣请求,涉及到多个挑战,我认为最容易的一个,结果是最难的。XAML使用来自目标控件的绑定路径在样式设置器中绑定

用户需要知道某个值已在本地更改,但尚未保留到后端存储。 (脏状态)我们用一个数据触发器解决了页面上每个控件声明的风格。当值被改变时,控制背景将被填充为黄色,然后当按下保存按钮时,将其重置回控制默认值。

模型视图实现了自定义接口:ILocalValueCache这有应该返回布尔值,表明自上次数据刷新当前值已更改的索引。

  • ModelView还实现IDataErrorInfo并使用DataAnnotations属性进行验证,所以我不能简单地使用验证模板。

我想什么做的是使用一个单一的样式或控件模板,这是困难的,因为每个控件现在有两个绑定,一个价值,另一个价值IsLocal简化XAML

更具体地说,我更喜欢一个解决方案,开发人员不需要知道它的工作原理(xIsLocal标记的字段名称)的内部机制,或者绑定源甚至支持它。

因为ViewModel实现了这个接口(和IDataErrorInfo一样),所以我应该能够全局定位绑定到接口描述的状态的控件样式。

这里是XAML的一些文本框的一部分:

  <TextBox Text="{Binding ScaleName}" Margin="5,2,5,2" Grid.Row="1" Grid.Column="2"> 
      <TextBox.Style> 
       <Style TargetType="{x:Type TextBox}"> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding ScaleNameIsLocal}" Value="True"> 
          <Setter Property="Background" Value="{StaticResource LocalValueBackgroundBrush}" /> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </TextBox.Style> 
     </TextBox> 
     <TextBox x:Name="nbScaleCap" Text="{Binding ScaleCap}" Grid.Row="3" Grid.Column="0" Margin="5,2,5,2"> 
      <TextBox.Style> 
       <Style TargetType="{x:Type TextBox}"> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding ScaleCapIsLocal}" Value="True"> 
          <Setter Property="Background" Value="{StaticResource LocalValueBackgroundBrush}" /> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </TextBox.Style> 
     </TextBox> 
     <TextBox x:Name="nbTareTol" Text="{Binding TareTol}" Grid.Row="3" Grid.Column="1" Margin="5,2,5,2"> 
      <TextBox.Style> 
       <Style TargetType="{x:Type TextBox}"> 
        <Style.Triggers> 
         <DataTrigger Binding="{Binding TareTolIsLocal}" Value="True"> 
          <Setter Property="Background" Value="{StaticResource LocalValueBackgroundBrush}" /> 
         </DataTrigger> 
        </Style.Triggers> 
       </Style> 
      </TextBox.Style> 
     </TextBox> 

除了索引,在视图模型的每个属性具有xxxIsLocal倒数属性,所以下面的部分模型对应以上面的例子:

string ScaleName { get; set; } 
bool ScaleNameIsLocal { get; set; } 
string ScaleCap { get; set; } 
bool ScaleCapIsLocal { get; set; } 
string TareTol { get; set; } 
bool TarTolIsLocal { get; set; } 

我已经使用该接口上的索引来获取IsLocal值各地播放,但INotifyPropertyChanged的实施挣扎(获取模式,以提高我ndexer值更改事件),除了更大的问题是如何使用基于目标控件上的内容或文本绑定路径的绑定而不是绑定结果的值创建单个样式。

我受到IDataErrorInfo模式的启发,并使用Validation.ErrorTemplate,它在表面看起来很简单,像这样一个简单的重复模式看起来像WPF应该能够处理的东西,没有太多问题。

我不知道多久我需要这个确切的模板,但它是一种模式,我敢肯定我想再次使用,其中每个属性有可能具有多个状态(不只是错误)并使用状态作为触发器应用不同的样式。


我已经编辑这个职位,因为我还没有完全找到我想要的东西,但多亏Nikkita我更近了一步:)

通过使用自定义的附加属性,我们可以直接在控件中声明绑定到标志字段,现在可以在全局样式字典中正确定义样式触发器。

视图模型并没有改变,但是从上面的XML现在simplifed:

<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}"> 
     <Style.Triggers> 
      <Trigger Property="att:IsLocal.Value" Value="True"> 
       <Setter Property="Background" Value="{StaticResource LocalValueBackgroundBrush}" /> 
      </Trigger> 
     </Style.Triggers> 
    </Style> 

<TextBox Text="{Binding ScaleName}" Margin="5,2,5,2" Grid.Row="1" Grid.Column="2" att:IsLocal.Value="{Binding ScaleNameIsLocal}"></TextBox> 
<TextBox Text="{Binding ScaleCap}" Grid.Row="3" Grid.Column="0" Margin="5,2,5,2" att:IsLocal.Value="{Binding ScaleCapIsLocal}"></TextBox> 
<TextBox Text="{Binding TareTol}" Grid.Row="3" Grid.Column="1" Margin="5,2,5,2" att:IsLocal.Value="{Binding TareTolIsLocal}"></TextBox> 

我与当前的解决方案最大的问题是,我仍然需要编辑很多如果我想将这个(或另一个)接口模式应用于现有的应用程序,则可以使用现有的XAML。即使在目前的形式中,也有超过20个字段,所以这20个机会可能会导致绑定错误,或者意外跳过一个。

+2

而不是使用这么多的国旗,你为什么不创建一个附加的广告载体像IsTextLocallyChanged文本框和创建一个单一的风格为所有textBoxes.Correct我,如果我错理解它。 –

+0

这不会绕过标志,但它应该解决样式问题,这将简化XAML。然后,我可以绑定到View模型中的标志。问题是视图模型包含标志,所以我们仍然需要声明XAML。你已经把我放在了正确的方向,但是......我将研究如何对自定义附加属性进行全局绑定 –

回答

0

我会建议你将“验证器”模式(看起来规范INotifyDataErrorInfo)与自定义行为相结合。 Validator根据项目中的绑定属性名称和Bahaviour更改元素来对结果进行包装。检查MSDN帮助。

Xaml Example: 
        <TextBox 
          Name="a" 
        Text="{Binding *Variable*, Mode=OneWay}" 
        Header="Start" 
        Style ="{StaticResource MitfahrenDefaultTextEdit}" IsReadOnly="true" 
        Tapped="StartLocation_OnTapped"> 
         <interactivity:Interaction.Behaviors> 
          <behaviors:RedFormFieldOnErrors 
           PropertyErrors="{Binding Path=Record.ValidationCollection[*Variable*]}"/> 
         </interactivity:Interaction.Behaviors> 
        </TextBox> 
+0

你是对的,我确实希望使用一种模式来验证Validator模式。事实上,这是这个问题的关键。但是我的控件已经有了验证模板,现在我想用额外的模板来扩展它们,比如如果值已经更改并且还没有被保存,那么还有验证。 –

+0

我可以做事情的界面和模型视图方面,但因为我想瞄准现有的控件(被密封),我认为最接近的东西,我可以拿出是某种自定义扩展,采取主要绑定路径和用于源代码中的自定义索引器。 我已经犯了错误,将模板绑定到了错误的属性上,我希望它是自动的,如果绑定源没有实现所需的接口,就会自动失败。 –

+0

所以一些背景逻辑的Attributes属性和反射引擎与旧值进行比较,并为索引器提供行为。行为可以是数据模板中的模板? –