I'm trying to display a variable that might change overtime, i tried this :
<Grid HorizontalAlignment="Left" Margin="2,5,0,0" VerticalAlignment="Top" Visibility="{Binding Req_Hexa}">
<TextBlock x:Name="myTextBox" HorizontalAlignment="Left" Height="106" Margin="270,95,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="187" Text= "{Binding Path = myText, ElementName=windowElement, Mode=TwoWay}" />
<TextBox x:Name="Val_Buffer_ReqHexa" HorizontalAlignment="Left" Height="Auto" Margin="52,0,0,0" TextWrapping="Wrap" Text="{Binding Buffer}" VerticalAlignment="Top" MinWidth="100" MaxWidth="500" KeyDown="Properties_KeyDown"/>
</Grid>
public string myText {get; set;}
public void test()
{
myText = " testttttttttttttttttttt";
}
The variable result is supposed to be displayed here but instead there is a blank
I tried every way of displaying a variable I could find
Try to set UpdateSourceTrigger to PropertyChanged:
<TextBlock Text= "{Binding myText, ElementName=windowElement, UpdateSourceTrigger=PropertyChanged}" />
<TextBox Text="{Binding Buffer, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
and implement INotifyPropertyChanged:
public string myText
{
get;
set
{
RaisePropertyChanged(myText);
}
}
public void test()
{
myText = " testttttttttttttttttttt";
}
public new event PropertyChangedEventHandler? PropertyChanged;
protected virtual void RaisePropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
Edit:
We got the problem. In WPF you need to have a Page (Diag_Prog.xaml) and a code behind file (Diag_Prog.xaml.cs) which are connected automatically. Just add a page to your project:
In Visual Studio it should look like this:
Related
I'm actually developping an UWP app who's reading Excel data, and display it on a form. Every Excel sheet are represented with RadioButton, and when the user click on a RadioButton, I update a ListView with the corresponding data.
Every item of the ListView have different data, and 2 checkboxes. This checkboxes can have the state "true" or "false", and if the user need to change the state, I want to modify his value
But the problem is, there is no event triggered with all the checkboxes when I check them. I tried to search and try to make my own template, but without success.
All the data are stored in a class :
public class REFERENCES
{
public int AI_ID { get; set; }
public int ID_poste { get; set; }
public string reference { get; set; }
public string designation { get; set; }
public bool avance { get; set; }
public bool jour { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
public REFERENCES(int ai_id, int id_poste, string ref_, string des_, string avance_, string jour_)
{
AI_ID = ai_id;
ID_poste = id_poste;
reference = ref_;
designation = des_;
if(jour_ != null)
{
jour = true;
}
else
{
jour = false;
}
if (avance_ != null)
{
avance = true;
}
else
{
avance = false;
}
}
public void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
And this is my ListView :
<ListView x:Name="ListViewData" SelectionMode="None" HorizontalAlignment="Center" Height="412" VerticalAlignment="Top" Width="650" Margin="0,218,0,0" >
<ListView.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="35" Margin="0,0,0,0" VerticalAlignment="Center" >
<TextBlock Text="AI_ID" Width="0" Visibility="Collapsed" />
<TextBlock Text="Désignations" FontSize="20" Width="300" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Références" FontSize="20" Width="150" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Avance" FontSize="20" Width="100" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
<TextBlock Text="Jour" FontSize="20" Width="100" Foreground="Blue" TextAlignment="Center" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</ListView.HeaderTemplate>
<ListView.ItemTemplate>
<DataTemplate x:DataType="ExcelLinkData:REFERENCES">
<StackPanel Orientation="Horizontal" >
<TextBlock Name="ItemAI_ID" Text="{x:Bind AI_ID}" Width="0" />
<TextBlock Name="ItemDesignation" Text="{x:Bind designation}" Width="300" FontSize="16" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center"/>
<TextBlock Name="ItemReference" Text="{x:Bind reference}" Width="150" FontSize="16" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center" TextAlignment="Center" />
<Grid Width="100" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
</Grid>
<Grid Width="100" Height="55" VerticalAlignment="Center" HorizontalAlignment="Center">
<CheckBox Name="ItemJour" IsChecked="{x:Bind jour}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
</Grid>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
The method "CHANGE_STATUS_REFERENCE" is the method where I want to change the state in my class.
I tried different solutions, but I'm not an expert in UWP, so if anyone got an advice, I'll take it !
Thanks in advance for your time !
Guillaume
In UWP, default mode for Binding is OneTime. And when you change property from viewmodel then no event is triggered. By changing Binding to OneWay / TwoWay (depending on your usage), viewmodel will trigger the event.
Change
IsChecked="{x:Bind jour}"
To
IsChecked="{x:Bind jour Mode=TwoWay}"
Change
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Checked="CHANGE_STATUS_REFERENCE"/>
to
<CheckBox Name="ItemAvance" IsChecked="{x:Bind avance}" Tag="{x:Bind AI_ID}" Command="{Binding CHANGE_STATUS_REFERENCE}"/>
Add a "Flip Function" to your class:
private void Flip()
{
this.avance = !this.avance;
}
Set up a RelayCommand:
RelayCommand _flipCommand = new RelayCommand(this.Flip);
and Implement CHANGE_STATUS_REFERENCE as an ICommand like so:
public ICommand CHANGE_STATUS_REFERENCE
{
get
{
return _flipCommand;
}
}
I am trying to learn about C# mvvm and wpf, so i decided to make a simple project(a book&readers managing application for a library) and now i am a little lost so i would really appreciate some help.
In my view i have a listview displaying the readers, and a bunch of textboxes bound to the selected item of the listview(name, adress,etc).
The listview is bound to an observable collection of readers created from a database table(Readers) with Linq2SQL.
Below the textboxes i have a few buttons (Clear/Add/Save/Delete).
The problems i am having are that the "selected item" of the listview, seems null if i try to execute some commands when i click the buttons.
when i click the clear button, if i have a breakpoint on the selected item(reader), it shows that it gets null/empty spaced, but the textboxes dont clear;
If in the Clear method in use the SelectedReader property, and assign empty spaces to its attributes, the selected item in the listview also clears(because its bound to Reader's FullName property)
i have other problems on adding a new reader, and saving changes, and i assume its because of wrong linq queries but i hope i can fix the current ones and move on afterwards.
What should i do?
ViewModel
public class MainWindowViewModel : ViewModelBase
{
private Reader selectedReader;
private ObservableCollection<Reader> readerList;
public MainWindowViewModel()
{
SelectedReader = new Reader()
{
FullName = "",
SerialNumber = "",
IdNumber = "",
Adress = "",
AltContactMethods = ""
};
BookDBDataContext rdb = new BookDBDataContext();
ReadersList = new ObservableCollection<Reader>(rdb.Readers);
AddR = new TblQryCommand(AddToDb);
EditR = new TblQryCommand(EditToDb);
DeleteR = new TblQryCommand(DeleteFromDb);
ClearR = new TblQryCommand(ClearReaderFields);
}
public TblQryCommand AddR { get; private set; }
public TblQryCommand EditR { get; private set; }
public TblQryCommand DeleteR { get; private set; }
public TblQryCommand ClearR { get; private set; }
//Reader List
public ObservableCollection<Reader> ReadersList
{
get { return readerList; }
set
{
if (readerList != value)
{
readerList = value;
RaisePropertyChanged();
}
}
}
public Reader SelectedReader
{
get { return selectedReader; }
set
{
if (selectedReader != value)
{
selectedReader = value;
RaisePropertyChanged();
}
}
}
public void AddToDb()
{
BookDBDataContext db = new BookDBDataContext();
Reader r = new Reader
{
FullName = SelectedReader.FullName,
SerialNumber = SelectedReader.SerialNumber,
IdNumber = SelectedReader.IdNumber,
Adress = SelectedReader.Adress,
AltContactMethods = SelectedReader.AltContactMethods
};
db.Readers.InsertOnSubmit(r);
db.Readers.Context.SubmitChanges();
}
public void DeleteFromDb()
{
}
public void EditToDb()
{
}
public void ClearReaderFields()
{
SelectedReader = new Reader
{
Id = 0,
FullName = string.Empty,
SerialNumber = string.Empty,
IdNumber = string.Empty,
Adress = string.Empty,
AltContactMethods = string.Empty
};
}
View:
<ListView Name="listviewReaders" ItemsSource="{Binding ReadersList}" SelectedItem="{Binding SelectedReader,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" Width="140" Height="180" Margin="10,68,492,281">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding FullName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBox x:Name="txtBxFullName" HorizontalAlignment="Left" Height="22" Margin="211,68,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.FullName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxSerialNumber" HorizontalAlignment="Left" Height="22" Margin="211,95,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.SerialNumber, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxIdNumber" HorizontalAlignment="Left" Height="22" Margin="211,122,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.IdNumber, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxAdress" HorizontalAlignment="Left" Height="22" Margin="211,149,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.Adress, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<TextBox x:Name="txtBxAltContactMethods" HorizontalAlignment="Left" Height="22" Margin="211,176,0,0" TextWrapping="Wrap" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.AltContactMethods, Mode=TwoWay, UpdateSourceTrigger=Explicit}" VerticalAlignment="Top" Width="315"/>
<Button x:Name="btnReader_Clear" Content="Clear" Command="{Binding ClearR}" HorizontalAlignment="Left" Margin="211,228,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnReader_Save" Content="Save" Command="{Binding EditR}" HorizontalAlignment="Left" Margin="291,228,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnReader_Add" Content="Add New" Command="{Binding AddR}" HorizontalAlignment="Left" Margin="371,228,0,0" VerticalAlignment="Top" Width="75"/>
<Button x:Name="btnReader_Delete" Content="Delete" Command="{Binding DeleteR}" HorizontalAlignment="Left" Margin="451,228,0,0" VerticalAlignment="Top" Width="75"/>
Have you tried to set the Binding of the Text-Property of your textboxes to your ViewModel's SelectedReader-Property directly?
So instead of writing this:
<TextBox x:Name="txtBxFullName" Text="{Binding ElementName=listviewReaders, Path=SelectedItem.FullName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" ... />
you would write:
<TextBox x:Name="txtBxFullName" Text="{Binding Path=SelectedReader.FullName, Mode=TwoWay, UpdateSourceTrigger=Explicit}" ... />
I have creating following GridRow as UserControl
<UserControl x:Class="Project.Telematics_Plugin.GridRow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" BorderBrush="LightBlue"
MaxHeight="30" MinWidth="900">
<Grid>
<StackPanel Orientation="Horizontal">
<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked}" />
<TextBox Width="60" Text="{Binding EventId}"/>
<TextBox Width="300" Text="{Binding MethodName}" />
<ComboBox Width="200" ItemsSource="{Binding }" />
<ComboBox Width="200"/>
<ComboBox Width="200"/>
<Button Click="OnClickEdit">
<Image Source="Images/edit.png"/>
</Button>
<Button Click="OnClickDelete">
<Image Source="Images/delete.png"/>
</Button>
</StackPanel>
</Grid>
</UserControl>
Here is the code behind
public partial class GridRow : UserControl
{
public bool IsChecked { get; set; }
public int EventId { get; set; }
public string MethodName { get; set; }
public string Level { get; set; }
public string Opcode { get; set; }
public string Task { get;set; }
public string Keyword { get; set; }
public GridRow()
{
InitializeComponent();
}
private void OnClickEdit(object sender, RoutedEventArgs e)
{
}
private void OnClickDelete(object sender, RoutedEventArgs e)
{
}
}
Now can you please tell what important thing I missed to bind properties of code behind files to UI in TwoWay Mode..
Although this is not the MVVM way..
Add an x:Name to your control and bind to the properties using ElementName:
<UserControl x:Name="MyGridRow">
<Grid>
<StackPanel Orientation="Horizontal">
<CheckBox VerticalAlignment="Center" IsChecked="{Binding IsChecked, ElementName=MyGridRow}" />
<TextBox Width="60" Text="{Binding EventId, ElementName=MyGridRow}"/>
<TextBox Width="300" Text="{Binding MethodName, ElementName=MyGridRow}" />
<ComboBox Width="200" ItemsSource="{Binding Path=., ElementName=MyGridRow}" />
<ComboBox Width="200"/>
<ComboBox Width="200"/>
<Button Click="OnClickEdit">
<Image Source="Images/edit.png"/>
</Button>
<Button Click="OnClickDelete">
<Image Source="Images/delete.png"/>
</Button>
</StackPanel>
</Grid>
</UserControl>
If you want to support updating the values, you should use DependencyProperties instead of normal properties:
public static readonly DependencyProperty IsCheckedProperty = DependencyProperty.Register("IsChecked", typeof(bool), typeof(GridRow));
public bool IsChecked
{
get { return (bool)GetValue(IsCheckedProperty); }
set { GetValue(IsCheckedProperty, value); }
}
when the DataContext where you use your usercontrol has all the properties IsChecked, EventId,MethodName ,..., then you can remove the properties from your usercontrol and all works.
but if you wanna create a "real" usercontrol then you should use DependencyProperties and bind them with the right expression within your usercontrol.
btw when you use Binding in WPF then its all about the right DataContext and the right BindingExpression
I am developing my first Windows 8 app, in one page i am trying to update button text with latest timestop when page loads. I defined my xaml and codebehind like below:
I am using databinding to update the button text but it is not working as expected:
MainPage.xaml
<Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
<Button HorizontalAlignment="Left" Margin="333,284,0,0" VerticalAlignment="Top" Height="69" Width="162">
<Button.Resources>
<DataTemplate x:Key="DataTemplate1">
<Grid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ButtonText}" VerticalAlignment="Top" Foreground="#FFFF6800" Height="34" Margin="-30,0,-22,-14" Width="115"/>
</Grid>
</DataTemplate>
</Button.Resources>
<Button.ContentTemplate>
<StaticResource ResourceKey="DataTemplate1"/>
</Button.ContentTemplate>
</Button>
</Grid>
MainPage.xaml.cs
public StatsClass Stats { get; private set; }
public MainPage()
{
this.InitializeComponent();
this.DataContext = Stats;
}
protected override void OnNavigatedTo(NavigationEventArgs e)
{
UpdateButton();
}
private void UpdateButton()
{
if (Stats == null)
Stats = new StatsClass();
Stats.ButtonText = DateTime.Now.ToString();
}
StatsClass.cs
public class StatsClass : INotifyPropertyChanged
{
private string _buttonText;
public string ButtonText
{
get
{
return _buttonText;
}
set
{
_buttonText = value;
OnPropertyChanged("ButtonText");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
You have set Content of your Button twice, once with Content="Button" and again with.Button.ContentTemplate. You could just have:
<Button HorizontalAlignment="Left" Margin="333,284,0,0" VerticalAlignment="Top" Height="69" Width="162">
<Grid>
<TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" Text="{Binding ButtonText}" VerticalAlignment="Top" Foreground="#FFFF6800" Height="34" Margin="-30,0,-22,-14" Width="115"/>
</Grid>
</Button>
I had a similar issue yesterday using binding in a DataTemplate. I guess that you also had a binding error in the debug output.
I solved it using a relative source like that:
<TextBlock Text={Binding DataContext.ButtonText,
RelativeSource={RelativeSource FindAncestor, AncestorType=*YourControl*}}"/>
The Template has no direct access to the datacontext. By using the relative source you can bind to its properties.
Here's the code for my window:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="leartWPF.ControlTestWindow"
x:Name="Window"
Title="ControlTestWindow"
Width="640" Height="480">
<Grid x:Name="LayoutRoot">
<TextBlock Height="26" Margin="45,26,241,0" TextWrapping="Wrap" Text="Please, enter an ariphmetical expression to calculate:" VerticalAlignment="Top"/>
<TextBox Margin="48,72,63,201" TextWrapping="Wrap" Text="{Binding Input, ElementName=Window, FallbackValue=1+1, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}" TextChanged="TextBox_TextChanged" >
</TextBox>
<!--<TextBlock Margin="282,208,266,167" TextWrapping="Wrap" Text="=" FontSize="64"/>-->
<TextBlock Height="90" Margin="83,0,77,60" TextWrapping="Wrap" VerticalAlignment="Bottom" FontSize="48" Text="{Binding Result, ElementName=Window, Mode=TwoWay}"/>
<Button Content="=" Height="27" Margin="233,0,263,166" VerticalAlignment="Bottom" FontSize="16"/>
</Grid>
</Window>
and the class:
public partial class ControlTestWindow : Window
{
private string _input;
public double Result { get; set; }
private static VsaEngine _engine = VsaEngine.CreateEngine();
public string Input
{
get { return _input; }
set
{
Result = double.Parse(Eval.JScriptEvaluate(value, _engine).ToString());
_input = value;
}
}
public ControlTestWindow()
{
this.InitializeComponent();
// Insert code required on object creation below this point.
}
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
}
}
The Input gets updated, and Result value changes, but it is never displayed on the appropriate TextBlock.
What should I change for this to work?
The TextBlock doesn't get notified of the change to the Result property. You have two options:
Implement the property as a DependencyProperty. Visual studio has a code snippet for it. Type propdp and you'll see it pop up in intellisense.
Implement INotifyPropertyChanged on your Window class and use it in your property.