2015-09-06 71 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屬性和反射引擎與舊值進行比較,併爲索引器提供行爲。行爲可以是數據模板中的模板? –