07-25-2013 04:17 AM
Hello,
i've a Problem by Setting the Range of an GaugeDouble with MVVM
Here is my Code that doesn't work. Hope anyboy can help me:
<ni:GaugeDouble Range="{Binding GaugeRange}" Value="{Binding Value}" Width="auto" /> and in my Viewmodel private Range<double> _GaugeRange; public Range<double> GaugeRange { get { return _GaugeRange; } set { _GaugeRange = value; NotifyPropertyChanged("GaugeRange"); } }
Thanks for your help
Solved! Go to Solution.
07-25-2013 10:27 AM
There is a known issue with how the numeric scale synchronizes its range with the numeric control when it is initialized. Instead of assigning Range
only after it has been edited interactively, it will assign it when the scale is initialized, overriding the binding.
Instead, you will need to use a two-way binding:
<ni:GaugeDouble Range="{Binding GaugeRange, Mode=TwoWay}" ... />
07-26-2013 12:57 AM
Hi Paul,
thanks for your Answer.
I tried the Two-Way Binding but it doesnt work!
I have
GaugeRange = new Range<double>(-900,900);
Is that ok ?
What else can i try ?
07-26-2013 09:57 AM
Here is the complete example I used to test the two-way binding:
Code
using NationalInstruments.Controls;
using System;
using System.ComponentModel;
using System.Windows;
namespace GaugeRangeBinding {
public class Model : INotifyPropertyChanged {
private Range<double> _GaugeRange = new Range<double>( -1.0, 1.0 );
public Range<double> GaugeRange {
get { return _GaugeRange; }
set {
_GaugeRange = value;
NotifyPropertyChanged( "GaugeRange" );
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged( string propertyName ) {
var handler = this.PropertyChanged;
if( handler != null )
handler( this, new PropertyChangedEventArgs( propertyName ) );
}
}
public partial class MainWindow : Window {
public MainWindow( ) {
InitializeComponent( );
}
private void OnMouseUp( object sender, EventArgs e ) {
var model = (Model)textBox.DataContext;
var range = model.GaugeRange;
model.GaugeRange = new Range<double>( range.Minimum, 2 * range.Maximum );
textBox.Text = model.GaugeRange.ToString( );
}
}
}
XAML
<Window x:Class="GaugeRangeBinding.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ni="http://schemas.ni.com/controls/2009/xaml/presentation"
xmlns:local="clr-namespace:GaugeRangeBinding"
Title="MainWindow" Height="300" Width="400">
<Grid>
<Grid.DataContext>
<local:Model />
</Grid.DataContext>
<ni:GaugeDouble Range="{Binding GaugeRange, Mode=TwoWay}" />
<TextBlock x:Name="textBox" MouseLeftButtonUp="OnMouseUp" />
</Grid>
</Window>
The XAML contains a text block that covers the screen, and clicking the text block causes the OnMouseUp
handler to change the range on the model, which updated the gauge via the binding.
07-29-2013 02:48 AM
Hello Paul,
thanks for your Answer. Your Example works fine. but in my Case it isn't working.
I've got the GaugeDouble in an DataTemplate
<DataTemplate x:Key="Gauge"> <Grid ContextMenu="{StaticResource cmenu}"> <Grid.RowDefinitions> <RowDefinition Height="30" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Label Grid.Row="0" Content="{Binding Title}" Padding="6,6,0,0" Background="#A0B2FF" BorderBrush="White" BorderThickness="1" FontSize="14"></Label> <Border BorderBrush="white" Background="Gainsboro" Grid.Row="1" BorderThickness="1,0,1,1" Width="200" Height="200"> <ni:GaugeDouble Range="{Binding GaugeRange, Mode=TwoWay}" Value="{Binding Value}" Width="auto" /> </Border> </Grid> </DataTemplate>
The DataTemplate is Used in an ItemsControl. That doesn't work. All other Controls where working fine.
What can be the Issue ?
07-29-2013 03:22 AM
Here is my complete Solution:
XAML:
<ItemsControl Grid.Column="0" Grid.ColumnSpan="3" AllowDrop="True" ItemsSource="{Binding Objects}" Background="Transparent" x:Name="DesigningCanvas" > <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <Canvas /> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.ItemContainerStyle> <Style > <Setter Property="Canvas.Left" Value="{Binding X,Mode=TwoWay}"/> <Setter Property="Canvas.Top" Value="{Binding Y,Mode=TwoWay}"/> </Style> </ItemsControl.ItemContainerStyle> <ItemsControl.ItemTemplate> <DataTemplate> <Grid> <Grid.RowDefinitions> <RowDefinition Height="30" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Label Grid.Row="0" Content="{Binding Title}" Padding="6,6,0,0" Background="#A0B2FF" BorderBrush="White" BorderThickness="1" FontSize="14"></Label> <Border BorderBrush="white" Background="Gainsboro" Grid.Row="1" BorderThickness="1,0,1,1" Width="200" Height="200"> <my:GaugeDouble Range="{Binding GaugeRange, Mode=TwoWay}" Value="{Binding Value}" Width="auto" /> </Border> </Grid> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </Grid>
The Model:
public class Model : INotifyPropertyChanged { private ObservableCollection<CanvasObject> _Objects; public ObservableCollection<CanvasObject> Objects { get { return _Objects; } set { _Objects = value; NotifyPropertyChanged("Objects"); } } public Model() { Objects = new ObservableCollection<CanvasObject>(); Objects.Add(new CanvasObject { Height = 200, Width = 200, X = 100, Y = 100 }); } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { var handler = this.PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } }
And here my Object:
public class CanvasObject : INotifyPropertyChanged { public CanvasObject() { } private string _Name; public string Name { get { return _Name; } set { _Name = value; Title = _Name; NotifyPropertyChanged("Name"); } } private string _Title; public string Title { get { return _Title; } set { _Title = value; NotifyPropertyChanged("Title"); } } private object _Value; public object Value { get { return _Value; } set { _Value = value; NotifyPropertyChanged("Value"); } } private double _Width; public double Width { get { return _Width; } set { _Width = value; NotifyPropertyChanged("Width"); } } private double _Height; public double Height { get { return _Height; } set { _Height = value; NotifyPropertyChanged("Height"); } } private Range<double> _GaugeRange = new Range<double>(50, 900); public Range<double> GaugeRange { get { return _GaugeRange; } set { _GaugeRange = value; NotifyPropertyChanged("GaugeRange"); } } private double _X; public double X { get { return _X; } set { _X = value; NotifyPropertyChanged("X"); } } private double _Y; public double Y { get { return _Y; } set { _Y = value; NotifyPropertyChanged("Y"); } } #region PropertyChanged Event Implementation public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyname) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyname)); } } #endregion }
The Binding of the Range-Property doesn't work in this case. But why ?
07-29-2013 01:51 PM
With your full code, I was able to reproduce the issue. I am not sure why the binding is being cleared on a control inside a data template, as opposed to the behavior outside.
As a workaround, I have found you can use a binding on a custom attached property that assigns the range directly:
XAML
...
<ni:GaugeDouble my:Extensions.Range="{Binding GaugeRange}" />
...
Code
public static class Extensions {
public static readonly DependencyProperty RangeProperty =
DependencyProperty.RegisterAttached(
"Range", typeof( Range<double> ), typeof( Extensions ),
new PropertyMetadata( OnRangeChanged ) );
public static Range<double> GetRange( DependencyObject d ) {
return (Range<double>)d.GetValue( RangeProperty );
}
public static void SetRange( DependencyObject d, Range<double> value ) {
d.SetValue( RangeProperty, value );
}
private static void OnRangeChanged( DependencyObject d, DependencyPropertyChangedEventArgs e ) {
var pointer = (NumericPointer<double, double>)d;
pointer.Range = (Range<double>)e.NewValue;
}
}
07-30-2013 01:26 AM
It works perfect
Thank you very much 🙂
08-11-2015 12:24 PM
Just wanted to let you know the Range
binding issue was fixed in the Measurement Studio 2015 release, and no longer needs the TwoWay
mode workaround.