I have a LineSeries to which I am binding the data from an ObservableCollection of the type ChartData. Now, In my UI, I have a TextBox in which I need to show the Y value of the series. How do I bind the Value property to the TextBox
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ObservableCollection<ChartData> lineSeries1Data = new ObservableCollection<ChartData>();
simChart.DataContext = lineSeries1Data;
}
public class ChartData : INotifyPropertyChanged
{
DateTime _Name;
double _Value;
public DateTime Name
{
get
{
return _Name;
}
set
{
_Name = value;
OnPropertyChanged("Name");
}
}
public double Value
{
get
{
return _Value;
}
set
{
_Value = value;
OnPropertyChanged("Value");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
This is my XAML for the TextBox:
<TextBox Name="TxtSignal1Vh1" DataContext="lineSeries1Data" Text="{Binding ChartData.Value}" />
Here is some Working Code,Create a Usercontrol consisting of Chart+textboxes and then binds its Datacontext to respective observable collection.
public MainWindow()
{
InitializeComponent();
observableCollection<DataChart>1st=new observableCollection<DataChart>();
observableCollection<DataChart>2nd=new observableCollection<DataChart>();
win.DataContext = (1st Observable Collection)
lose.DataContext=(2nd Observable Collection)
}
MainWindows xaml
<Grid>
<this:UserControl1 x:Name="win" Margin="10,21,325,144"/>
<this:UserControl1 x:Name="lose" Margin="275,21,10,144"/>
</Grid>
UserControl xaml
<Grid>
<TextBox Text="{Binding Path=Value}" VerticalAlignment="Top" Width="164"/>
<TextBox Text="{Binding Path=Name}" VerticalAlignment="Top" Width="164"/>
</Grid>
Related
I'm trying to group various sliders elements to work together. In example if I have two elements, both are set to 50 (values goes from 0 to 100), the sum of the values must be always 100, so if I set one of the sliders to value 70, the other one must decrease dynamically to 30 value.
<ListView x:Name="listView"
ItemSource="myList">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Slider x:Name="slider"
Maximum="100"
Minimum="0"
Value="{Binding MyValue}"
HorizontalOptions="FillAndExpand"
MinimumTrackColor="Black"
MaximumTrackColor="Black"
ThumbColor="{StaticResource myColor}"
ValueChanged="OnValueChanged"
PropertyChanging="ChangingSliderValue"/>
<Label Text="{Binding Source={x:Reference slider}, Path=Value, StringFormat='{0:0}'}"
FontSize="Medium"
FontAttributes="Bold"
HorizontalOptions="End"
WidhtRequest="40"/>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The C# class of my objects is
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private int _value;
private string _name;
private bool _someBool;
public int MyValue { get {return _value;} set {_value = value;} }
public string Name { get {return _name;} set {_name = value;} }
public bool SomeBool { get {return _someBool;} set {_someBool = value; OnPropertyChanged();} }
void OnPropertyChanged ([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And part of the class of the Xaml page is:
namespace MyApp
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SliderPage: ContentPage
{
private ObservableCollection<MyClass> list = new ObservableCollection<MyClass>();
...
public SliderPage ()
{
InitializeComponent();
InitList();
listView.ItemsSource = list;
...
}
private void InitList () ...
private void ChangingSliderValue (object sender, PropertyChangedEventArgs e)
{
//Code to stick together the slider...
}
}
Any suggestion of how to achieve my goal?
work but is not showing dynamically
You need to implement the interface INotifyPropertyChanged on property MyValue so that the element will update in runtime .
By the way , since you had used data binding in your project . It would be better to handle logic in ViewModel. So you could modify the code like following
in Xmal
<ListView
ItemsSource="{Binding MySource}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" HeightRequest="300" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Slider x:Name="slider"
Maximum="100"
Minimum="0"
Value="{Binding MyValue,Mode=TwoWay}"
HorizontalOptions="FillAndExpand"
MinimumTrackColor="Black"
MaximumTrackColor="Black"/>
<Label Text="{Binding Source={x:Reference slider}, Path=Value, StringFormat='{0:0}'}"
FontSize="20"
FontAttributes="Bold"
WidthRequest="40"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
in Code behind
Model
public class MyClass : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Id { get; set; } // add this property to index the slider
private int _value;
private string _name;
private bool _someBool;
public int MyValue {
get
{
return _value;
}
set
{
if(_value!=value)
{
_value = value;
OnPropertyChanged("MyValue");
}
}
}
public string Name { get { return _name; } set { _name = value; } }
public bool SomeBool { get { return _someBool; } set { _someBool = value; OnPropertyChanged("SomeBool"); } }
void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
ViewModel
public class MyViewModel
{
public ObservableCollection<MyClass> MySource { get; set; }
bool isFirstLoad = true;
public MyViewModel()
{
MySource = new ObservableCollection<MyClass>() {
new MyClass(){MyValue = 50,Id=0 },
new MyClass(){MyValue = 50,Id=1 },
};
foreach (MyClass model in MySource)
{
model.PropertyChanged += Model_PropertyChanged;
}
}
private void Model_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName== "MyValue")
{
//handle your logic here as you need
MyClass model = sender as MyClass;
foreach (MyClass item in MySource)
{
if (model.Id != item.Id)
{
item.MyValue = 100 - model.MyValue;
}
}
}
}
}
ContentPage
public xxxPage()
{
InitializeComponent();
BindingContext = new MyViewModel();
}
I have following textbox binding:
XAML:
<TextBlock x:Name="Auslastungskapazität1" Text="{Binding Kapazität, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Foreground="Black" HorizontalAlignment="Center" Margin="0,5,5,5" FontSize="16" ></TextBlock>
MainViewModel Class:
class MainViewModel: ZuliefererStandortListe, IDropTarget, INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public int Kapazität {
get { return _kapazität1Ausgelastet; }
set {
if (this._kapazität1Ausgelastet != value)
_kapazität1Ausgelastet = value;
OnPropertyChanged("Kapazität");
}
}
public void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
DataContext is the in the MainWindow Constructor as
Kapazität.DataContext = new MainViewModel();
If I change Kapazität the int get changed and the OnPropertyChanged() method gets called. However "PropertyChanged" remains null and therefore the Textbox Binding doesn't get updated.
Either set the DataContext of the TextBox itself:
Auslastungskapazität1.DataContext = new MainViewModel();
...or of any of its parent elements, such as for example the window:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewModel();
}
}
I tried to bind a property to a nested object, but it fails.
I have taken a look at those questions, but i think i made another mistake somewhere else. Maybe someone can give i hind.
WPF: How to bind to a nested property?
binding to a property of an object
To upper slider/textbox has a correct binding while the lower one fails to do so.
I have two sliders with corrosponding textboxes:
<StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBox Text="{Binding Path= boundnumber, Mode=TwoWay, FallbackValue='binding failed'}" ></TextBox>
<Slider Value="{Binding Path= boundnumber, Mode=TwoWay}" Width="500" Maximum="1000" ></Slider>
</StackPanel>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" DataContext="{Binding Path=myDatarow}">
<TextBox Text="{Binding Path= boundnumber, Mode=TwoWay, FallbackValue='binding failed'}" ></TextBox>
<Slider Value="{Binding Path= boundnumber, Mode=TwoWay}" Width="500" Maximum="1000" ></Slider>
</StackPanel>
</StackPanel>
Code behind:
public partial class MainWindow : INotifyPropertyChanged
{
public MainWindow()
{
DataContext = this;
InitializeComponent();
}
private int _boundnumber;
public int boundnumber
{
get { return _boundnumber; }
set
{
if (value != _boundnumber)
{
_boundnumber = value;
OnPropertyChanged();
}
}
}
Datarow myDatarow = new Datarow(11);
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
}
class Datarow : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyname = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyname));
}
public Datarow()
{
}
public Datarow(int number)
{
boundnumber = number;
}
private int _boundnumber;
public int boundnumber
{
get { return _boundnumber; }
set
{
if (value != _boundnumber)
{
_boundnumber = value;
OnPropertyChanged();
}
}
}
}
You need to expose your myDatarow into a public property like your boundnumber.
private DataRow _myDatarow = new DataRow(11);
public DataRow myDataRow
{
get { return _myDatarow; }
}
And just an additional advice.
It's better to separate your DataContext class from the MainWindow.
I know I should use the MVVM pattern but I'm trying to get step by step closer to it. So here is my Listbox:
<ListBox x:Name="BoardList" ItemsSource="{Binding notes}" >
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
<TextBox IsReadOnly="True" ScrollViewer.VerticalScrollBarVisibility="Visible" Text="{Binding text}" TextWrapping="Wrap" Foreground="DarkBlue"></TextBox>
<AppBarButton Visibility="{Binding visibility}" Icon="Globe" Click="OpenInBrowser" x:Name="Link"></AppBarButton>
<AppBarButton Icon="Copy" Click="Copy"></AppBarButton>
<AppBarButton Icon="Delete" Click="Delete"></AppBarButton>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In the Mainpage.xaml.cs I declare the following:
ObservableCollection<BoardNote> notes = new ObservableCollection<BoardNote>();
So if I understood this right I don't need to care about the "INotifyCollectionChanged" stuff because I'm using an observablecollection?
So I got for example a textbox like this:
<Textbox x:Name="UserInputNote" Placeholdertext="Type in a text for your note"></Textbox>
And a button to Add the new note to the ObservableCollection and the click event is just like this:
notes.Add(new BoardNote(UserInputNote.Text));
So now the UI should update every time the user clicks the button to save a new note. But nothing happens. What did I do wrong?
If you need it here is the BoardNote class:
class BoardNote
{
public string text
{
get; set;
}
public BoardNote(string text)
{
this.text = text;
}
public Visibility visibility
{
get
{
if (text.StartsWith("http"))
return Visibility.Visible;
else
return Visibility.Collapsed;
}
}
}
You need to implement INotifyPropertyChanged. Here's one way of doing it.
Create this NotificationObject class.
public class NotificationObject : INotifyPropertyChanged
{
protected void RaisePropertyChanged<T>(Expression<Func<T>> action)
{
var propertyName = GetPropertyName(action);
RaisePropertyChanged(propertyName);
}
private static string GetPropertyName<T>(Expression<Func<T>> action)
{
var expression = (MemberExpression)action.Body;
var propertyName = expression.Member.Name;
return propertyName;
}
private void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public event PropertyChangedEventHandler PropertyChanged;
}
Then your BoardNote class will inherit it this way:
class BoardNote : NotificationObject
{
private string _text
public string Text
{
get {return _text;}
set
{
if(_text == value) return;
_text = value;
RaisePropertyChanged(() => Text);
}
}
public BoardNote(string text)
{
this.text = text;
}
public Visibility visibility
{
get
{
if (text.StartsWith("http"))
return Visibility.Visible;
else
return Visibility.Collapsed;
}
}
}
I want to bind my StackPanel component to an object and its properties to elements it the StackPanel
<StackPanel Grid.Column="0" Grid.Row="0" Name="device1" Background="#CC119EDA" DataContext="{Binding}">
<Label FontSize="22" Foreground="White">Desk #1</Label>
<TextBox Text="{Binding Name}" />
</StackPanel>
In code behind
device1.DataContext = new Class { Name = "Name" };
What is wrong with this binding? Thanks
You could try like this. When u set the property to the Object , the UI Thread is not aware of the change , so you need to Implement RaisePropertyChange Mechanism. Using MvvmLight Toolkit is great advantage . Here the window datacontext is set to so could inherit all elements.
public partial class MainWindow : Window, INotifyPropertyChanged
{
private string _name;
public string MyName
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged("MyName");
}
}
public MainWindow()
{
InitializeComponent();
MyName = "Eldho";
this.DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}
Xaml
<StackPanel>
<Label>Hi,</Label>
<TextBox Text="{Binding MyName}"/>
</StackPanel>