2016-08-19 95 views
3

我正在處理使用WPF和MVVM顯示罐中液體水平的顯而易見的簡單問題。如何從ViewModel轉換信息以顯示在視圖中

爲了顯示一個坦克,我使用了一個帶有矩形的DockPanel。矩形的高度根據儲罐中的液體量而變化。在坦克的頂部,我有一個TextBlock,顯示坦克中存在的液體數量。 我在XAML定義這個是這樣的:

<DockPanel x:Name="tankView" HorizontalAlignment="Left" Height="212" VerticalAlignment="Top" Width="144" DataContext="{Binding Source={StaticResource TankViewModel}}"> 
      <TextBlock x:Name="oilQuantity" HorizontalAlignment="Right" VerticalAlignment="Top" DockPanel.Dock="Top" Margin="0,0,10,0" Text = "{Binding TxtOilQuantity, Mode=OneWay}"/> 
      <Rectangle x:Name="oilLevel" Fill="Green" Height="66" Stroke="Black" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" DockPanel.Dock="Bottom"/> 
</DockPanel> 

你也可以看到,我創建了一個TankViewModel類和TankModel類,MVVM模式下。

顯示TextBlock中的液體數量很簡單,並且數據綁定完美地完成了這項工作。但是,當涉及到矩形的高度時,會出現一些問題,因爲我無法找到正確分離視圖和ViewModel之間關係的方法。

Rectangle的高度取決於最大容量和存在的液體在坦克的數量,這樣我可以得到一個數字,告訴我在什麼比例的坦克被填滿,這樣的:

public class TankViewModel : INotifyPropertyChanged 
{ 
    private TankModel tankModel = new TankModel(2500); 

    public int IntFilledPercentage { 
     get { 
      if (tankModel.OilQuantity == 0) 
       return 0; 
      else 
       return Convert.ToInt32(((double)tankModel.OilQuantity/tankModel.capacity) * 100); 
     } 
    } 

    public event PropertyChangedEventHandler PropertyChanged; 

    protected void NotifyPropertyChanged(String info) { 
     if (PropertyChanged != null) { 
      PropertyChanged(this, new PropertyChangedEventArgs(info)); 
     } 
    } 
} 

但是,我無法將此屬性直接綁定到矩形的高度,併爲這樣的屬性賦予值聽起來像視圖應該負責的事情。 爲了實現這一點,我將不得不在視圖中插入一些代碼,將此百分比值轉換爲矩形的高度。

我可以通過實現視圖的OnPropertyChanged()回調來實現這一點嗎?

對於如何簡化我所採用的架構,您有什麼建議嗎?

回答

2

補充rory。如果您不想使用固定的Converter參數,但使用某個容器的實際高度,則還可以使用MultiBindingIMultiValueConverter

這可以使用父級的實際高度來設置液體的高度。

在我的示例中,我使用帶邊框的網格來表示gui上的液體罐。

視圖模型:

public class MainWindowViewModel : PropertyChangedBase // from Calburn.Micro (see nuget) 
{ 
    private int _liquidPerc; 

    public MainWindowViewModel() 
    { 
     LiquidPercentage = 25; 
    } 

    public int LiquidPercentage 
    { 
     get { return _liquidPerc; } 
     set 
     { 
      if (value == _liquidPerc) return; 
      _liquidPerc= value; 
      NotifyOfPropertyChange(() => LiquidPercentage); 
     } 
    } 
} 

轉換器:

/// <summary> 
/// Converter which expects two params. percentage and maximum height 
/// </summary> 
public class LiquidLevelConverter : IMultiValueConverter 
{ 
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) 
    { 
     var percentage = (int) values[0]; 
     var maxHeight = (double) values[1]; 
     return percentage*maxHeight*0.01; 
    } 

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

XAML:

<Window x:Class="UiLiquedTankDemo.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
     xmlns:local="clr-namespace:UiLiquedTankDemo" 
     xmlns:system="clr-namespace:System;assembly=mscorlib" 
     mc:Ignorable="d" 
     Title="MainWindow" Height="350" Width="525"> 
    <Window.Resources> 
     <local:MainWindowViewModel x:Key="ViewModel" /> 
     <local:LiquidLevelConverter x:Key="LiquidLevelConverter" /> 
    </Window.Resources> 
    <DockPanel DataContext="{StaticResource ViewModel}"> 

     <!-- move the slider to move the level of the liquid --> 
     <Slider Minimum="0" Maximum="100" Value="{Binding LiquidPercentage}" 
       DockPanel.Dock="Bottom" 
       Margin="0"/> 

     <!-- Liquid container representation using a grid --> 
     <Grid Name="LiquidContainer" Margin="200,5"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="*"/> 
       <RowDefinition Height="Auto"/> 
      </Grid.RowDefinitions> 

      <Border Grid.Row="1" Background="Blue" Margin="0"> 
       <Border.Height> 
        <MultiBinding Converter="{StaticResource LiquidLevelConverter}"> 
         <Binding Path="LiquidPercentage"></Binding> 
         <Binding Path="ActualHeight" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type Grid}}"></Binding> 
        </MultiBinding> 
       </Border.Height> 
      </Border> 

      <Border Grid.Row="0" Grid.RowSpan="2" BorderBrush="Black" BorderThickness="1" /> 
     </Grid> 

    </DockPanel> 
</Window> 
+0

標誌着我這是接受的解決方案,因爲我要考慮到容器的實際高度而不是硬編碼它。 Rory和toadflakz的答案也非常有幫助,謝謝! – Perennialista

4

通過使用一點數學算法,您可以使用視圖模型中的百分比值輕鬆完成此操作。你知道視圖中矩形的最大高度(可能是一個靜態值)。然後當前高度=最大高度乘以百分比值。

在XAML中執行這樣的操作可以使用the Binding.Converter property with an IValueConverter完成。請參閱this post,這是相關的。

下面是一個例子轉換器:

internal sealed class OilLevelConverter : System.Windows.Data.IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     var percentage = (decimal) value; 
     var maxLevel = System.Convert.ToInt32((string) parameter); 
     var currentLevel = System.Convert.ToInt32(maxLevel * percentage); 
     return currentLevel; 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

這是你的App.xaml

<Application x:Class="WpfApplication1.App" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:local="clr-namespace:WpfApplication1" 
      StartupUri="MainWindow.xaml"> 
    <Application.Resources> 
     <local:ViewModel x:Key="ViewModel" /> 
     <local:OilLevelConverter x:Key="OilLevelConverter"/> 
    </Application.Resources> 
</Application> 

這裏是一個例子窗口XAML:

<Window x:Class="WpfApplication1.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" 
     Width="525" 
     DataContext="{StaticResource ViewModel}" > 

    <Grid> 
     <Rectangle Fill="#FFF4F4F5" 
        HorizontalAlignment="Left" 
        Height="{Binding Path=OilLevel, 
        Converter={StaticResource OilLevelConverter}, 
        ConverterParameter=100}" Margin="183,132,0,0" 
        Stroke="Black" VerticalAlignment="Top" Width="100"/> 
    </Grid> 
</Window> 

注:我已經離開了ViewModel其中只有一個屬性:OilLevel

1

使用一個ValueConverter從ViewModel值IntFilledPercentage翻譯爲矩形的填充值爲Height

您將在IntFilledPercentage視圖模型屬性爲RectangleHeight屬性綁定,然後進行轉換,從百分比在Converter類實際視覺單位。

<Rectangle x:Name="oilLevel" Fill="Green" Height="{Binding IntFilledPercentage, Mode=OneWay, Converter={StaticResource PercentageToHeightConverter}" Stroke="Black" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" DockPanel.Dock="Bottom"/> 

轉換器實現IValueConverter接口。在這種情況下,您只需要執行Convert()

相關問題