This is my first question so be careful :)
i'm trying to do a binding of the property (a) in the xaml, the foreground color works(so the ref of the datagrid cell is right), but the background not and i'm trying to understand why, if i try to debug my property the program doesnt enter in it....
(a)=
public int CellGiorno1
{
get
{
int a = myfunctionexample(day, Username, month, year);
return a;
//return 0-1-2
}
}
(the column of the datagrid where i want to color the background if the number returned is 1)
DataGridTextColumn Header="2" x:Name="HeaderGG1" Binding={Binding Desc_GG1}" CellStyle="{StaticResource CellStyleGiorno}"/>
(the style with the trigger that color the foreground but not the background)
<Style x:Key="CellStyleGiorno" TargetType="DataGridCell">
<Setter Property="Foreground" Value="Red"/>
<Style.Triggers>
<DataTrigger Binding="{Binding CellGiorno1}" Value="1">
<Setter Property="Background" Value="Green"/>
</DataTrigger>
</Style.Triggers>
</Style>
The first problem here is your get and set methods. Take a look at this structure:
class Name
{
private string _mynam = "";
public string mynam
{
set
{
_mynam = value;
}
get
{
return _mynam;
}
}
}
You don't have the set method and you set the method in the get method.
the property need to have a notification of change structure attached to it to enable binding
this is usually done with INotifyPropertyChanged or DependencyProperty
eg
public class myClass :INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void ChangeCell()
{
PropertyChanged(this,new PropertyChangedEventArgs("CellGiorno1")
}
public int CellGiorno1
{
get
{
int a = myfunctionexample(day, Username, month, year);
return a;
//return 0-1-2
}
}
}
so in this case calling ChangeCell would notify all bindings connected to CellGiorno1 that they need to get the value of CellGiorno1 because its changed
Related
I am trying to make a ComboBox where the drop-down list shows the name and description of the campaign elements (properties NombreCampana and Descripcion of class Campana) and when you select one value it shows the Name (NombreCampana). I have done this with an ObservableCollection so the changes affect the ComboBox without reloading.
In the MainMenu window (menuPrincipal), I have this XAML for the ComboBox:
<ComboBox Style="{DynamicResource comboBoxCampaign}"
x:Name="campaignComboBox"
Text="{DynamicResource CampaignList}"
ItemsSource="{Binding Path=Nombres}"
SelectedValue="{Binding Path=NombreCampana, Mode=TwoWay}"
SelectedValuePath="Value"
SelectionChanged="CampaigneComboBox_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat="{}{0}
{1}">
<Binding Path="NombreCampana"/>
<Binding Path="Descripcion"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
The ComboBox, is linked to an ObservableCollection in the code-behind:
private List<Campana> listacampana = new List<Campana>();
private ObservableCollection<Campana> nombres = new ObservableCollection<Campana>();
public ObservableCollection<Campana> Nombres
{
get { return nombres; }
set { nombres = value; }
}
public List<Campana> ListaCampanas
{
get { return listacampana; }
set { listacampana = value; }
}
public menuPrincipal()
{
InitializeComponent();
ConfiguracionPagina.DefinirIdioma(this, "MainMenu");
this.listacampana.AddRange(MainWindow.DatosUsuario.ListCampaigns);
foreach (Campana item in this.listacampana)
{
this.nombres.Add(item);
}
campaignComboBox.ItemsSource = this.nombres;
}
That code defines the language, changes the texts, adds the user list to the property list, and after that adds to the all the items Campana (campaign) to the ObservableCollection.
After that I set the ItemSource of the ComboBox to Nombres (the ObservableCollection).
The class Campana is:
public class Campana
{
private string nombre;
private string descripcion;
private string imagen;
private List<RecursosCampana> listarecursos = new List<RecursosCampana>();
public string DireccionImagen
{
get { return imagen; }
set { imagen = value; }
}
public List<RecursosCampana> RecursosCampana
{
get { return listarecursos; }
set { listarecursos = value; }
}
public string Descripcion
{
get { return descripcion; }
set { descripcion = value; }
}
public string NombreCampana
{
get { return nombre; }
set { nombre = value; }
}
}
When I run the application, the DataTemplate works fine and shows the items with the description.
But when I select one item I get this:
I have tried everything that I founded by searching Google, but I don't get what is happening. Also, if I don't define the ItemSource in the code, the XAML ItemSource doesn't work. This is what happens if I comment out campaignComboBox.ItemsSource = this.nombres;:
Edit: answering the comments, i have solved thanks to #Keith Stein, a part of the problem, this was the style
<Style x:Key="comboBoxCampaign" TargetType="ComboBox">
<Setter Property="Margin" Value="10"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="IsEditable" Value="True"/>
<Setter Property="IsReadOnly" Value="True"/>
<Setter Property="Focusable" Value="True"/>
<Setter Property="FontSize" Value="15"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Height" Value="Auto"/>
</Style>
I used that to have a "placeholder" text, an initial text which is going to dissapears once you click in the combobox, when i delete "IsEditable" i lost the initial title the combobox just have the V to press, but now when i select an item, i get the name + description.
Is not exactly what i want, i just want to show the name, but is more close to that.
Edit2: The problem with the databinding was that i didnt use the DataContext = this; now i can get the bind from xaml but still i cant show just the name.
Lastly answering to the last comment, what i am trying to do is:
- I'm doing an application to prepare roleplaying adventures or scenarios, in this section the user select the campaign that he is going to use, so i want that when he press the combobox, he can see the name of the campaign and the description because he could have 2 similar campaigns or based in the same system, and once he choose one, just show the name that is more elegant specially if he writes a big description
Finally i get the answer in this post Can I use a different Template for the selected item in a WPF ComboBox than for the items in the dropdown part?
Simple swapping between two templates if the item is selected or not.
I am still fairly new to WPF and MVVM. I added a DataGridComboBoxColumn to a DataGrid. Binding to the view object works fine. However when I re-open the screen after saving the combobox does not display the value previously saved (basically binding from view back to UI does not work).
Below is an idea of what I am trying to do:
The below three classes are my view classes
ViewPosition is the class type of the rows in my data grid (see XAML below). ViewPosition contains a reference to ViewPricing.
ViewPricing contains a reference to a parentSecurity (string type).
Security is a security containing a Description property.
public class ViewPosition : INotifyPropertyChanged
{
private long _securityID;
private long _portfolioID;
private DateTime _positionDate;
private ViewPricing viewPricing;
public ViewPricing Pricing
{
get { return viewPricing; }
set
{
viewPricing= value;
NotifyPropertyChanged();
}
}
}
public class ViewPricing : INotifyPropertyChanged
{
private String parentSecurity;
private decimal quantity;
private decimal price;
private decimal yield;
private decimal spread;
public string ParentSecurity
{
get { return parentSecurity; }
set
{
if (parentSecurity != value)
{
parentSecurity = value;
NotifyPropertyChanged("parentSecurity");
}
}
}
}
public class Security : INotifyPropertyChanged
{
public string Description { get; set; }
}
Here is my view model. This fetches a list of all available securities.
public class PositionViewModel : INotifyPropertyChanged
{
private List<Security> _securities;
private List<Security> _securities;
public List<Security> Securities
{
get { return _securities; }
set
{
if (_securities != value)
{
_securities = value;
NotifyPropertyChanged();
}
}
}
Finally here is my XAML.
I want the user to see the security description in the combo box. This is why I set DisplayMemberPath="Description".
Upon saving I want the combo box value to be saved in Pricing.ParentSecurity. This is why I set SelectedValueBinding and SelectedValuePath as below.
The list of securities shows correctly the combo box. The binding to the view object is working (combobox value is saved to Pricing.ParentSecurity). The problem I am having is that the binding from view object back to UI (combo box) does not work. If close then re-open my window then the combo box doesn't show the value (it is blank).
<DataGrid.Columns>
<DataGridComboBoxColumn Header="Parent Security" SelectedValueBinding="{Binding Path=Pricing.ParentSecurity, Mode=TwoWay}" SelectedValuePath="Description" DisplayMemberPath="Description"/>
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.Securities, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
<Setter Property="IsReadOnly" Value="True"/>
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.Securities, RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
</DataGrid.Columns>
Thanks for any help/suggestions you can provide!
I'm having a TextBox, if the TextBox has the Text.Length >0 then I have to change the HasChar property True otherwise False. Here I can't able to Bind the Property in the Setter.
The XAML Source Code:
<TextBox Text="WPF">
<TextBox.Style>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<DataTrigger Value="0"
Binding="{Binding Text.Length, RelativeSource={RelativeSource Self}}">
<Setter Property="{Binding HasChar}" Value="False" />
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
The View Model C# Source Code :
private bool _hasChar= true;
public bool HasChar
{
get { return _hasChar; }
set
{
_hasChar= value;
OnPropertyChanged();
}
}
You're misusing triggers.
The right way to go:
1) XAML:
<TextBox Text="{Binding Text, UpdateSourceTrigger=PropertyChanged}"/>
2) view model. You don't need to add setter to HasChar. If this property is bound to something in view, just raise appropriate PropertyChanged:
public class ViewModel : INotifyPropertyChanged
{
// INPC implementation is omitted
public string Text
{
get { return text; }
set
{
if (text != value)
{
text = value;
OnPropertyChanged();
OnPropertyChanged("HasChar");
}
}
}
private string text;
public bool HasChar
{
get { return !string.IsNullOrEmpty(Text); }
}
}
You can not bind a property in the setter. Style is used to set the UI element properties like Text,Visibility,Foreground etc.
I have a WPF DataGridCheckBoxColumn, which is bound to an object that implements INotifyPropertyChanged as shown below:
DataGridCheckBoxColumn Binding="{Binding Path=IsSelected}" CellStyle="{StaticResource MyDataGridCheckBoxCellStyle}"/>
Here is the associated object:
public class ListItem : INotifyPropertyChanged
{
public int ID { get; set; }
private bool isSelected = false;
public bool IsSelected { get { return isSelected; } set { isSelected = value; OnChanged("IsSelected"); } }
public event PropertyChangedEventHandler PropertyChanged;
private void OnChanged(string prop)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(prop));
}
}
Everything works as expected, except that in order to set the Checkbox to Checked, I need to double click, in order to first select the column, and then set the checkbox value.
So, I decide to implement a Style trigger as shown below:
<Style x:Key="MyDataGridCheckBoxCellStyle" TargetType="DataGridCell">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True" >
<Setter Property="IsEditing" Value="True" />
</Trigger>
</Style.Triggers>
</Style>
Now I am able to single click to Check the Checkbox, but my binding doesn't work anymore. Any idea of what is going on here? Why does setting the Style Trigger remove the binding?
Changing the style can cause some issues with the default template. You would most likely need to copy the entire style + template and then modify that to suit your needs. You could try this http://wpf.codeplex.com/wikipage?title=Single-Click%20Editing however.
my problem is here:
I have some class
public class Component
{
...
private ServiceController service;
...
public int ServiceStatus
{
get
{
switch(service.Status)
{
case ServiceControllerStatus.Stopped:
return 0;
case ServiceControllerStatus.Running:
return 1;
default:
return 2;
}
}
}
public void QueryService()
{
service.Refresh();
}
}
and collection of Components, declared in another class:
public class Motivation
{
// Downloaded data
...
private ObservableCollection<Component> components;
public ObservableCollection<Component> Components
{
get { return components; }
}
public bool CheckServices()
{
bool changed = false;
foreach (Component C in components)
{
int prevStatus = C.ServiceStatus;
C.QueryService();
if (prevStatus != C.ServiceStatus)
changed = true;
}
return changed;
}
This components list displayed in WPF DataGrid. My idea: green background color for running services, red - for stopped. Works fine, but only on start. CheckServices() called by timer, and if returned value is True, i want to rerender my grid, respect to new service statuses. Here is XAML:
<Style x:Key="ServiceStateStyle" TargetType="z:DataGridRow">
<Setter Property="Background" Value="Gray" />
<Style.Triggers>
<DataTrigger Binding="{Binding Path=ServiceStatus}" Value="0">
<Setter Property="Background" Value="LightCoral" />
</DataTrigger>
<DataTrigger Binding="{Binding Path=ServiceStatus}" Value="1">
<Setter Property="Background" Value="LightGreen" />
</DataTrigger>
</Style.Triggers>
</Style>
<z:DataGrid Grid.Row="0"
Grid.ColumnSpan="4"
AutoGenerateColumns="False"
x:Name="DataGridComponents"
ItemContainerStyle="{DynamicResource ServiceStateStyle}">
<z:DataGrid.Columns>
<z:DataGridTextColumn IsReadOnly="True"
Header="Component" Width="80"
Binding="{Binding Path=DisplayName}"/>
</z:DataGrid.Columns>
</z:DataGrid>
Should i call any method explicit to invalidate DataGrid? I have tried with InvalidateProperty, InvalidateVisual, GetBindingExpression(ItemContainerStyleProperty).UpdateTarget(), but nothing work. Can anyone help?
The Component class must implement the INotifyPropertyChanged and raise the event when some of it's property change.