I have this WPF structure:
<UserControl
xmlns:viewModel="clr-namespace:..ViewModel.ToneAudiogramLegend">
...
<DataTemplate DataType="{x:Type viewModel:ToneAudiogramLegendTableViewModel}">
...
<DataGrid Grid.Row="1" Grid.Column="0" ItemsSource="{Binding ToneAudiogramLegneds}" HeadersVisibility="None" AutoGenerateColumns="False" IsReadOnly="True" BorderBrush="Transparent" BorderThickness="0"
MinWidth="100" Height="{Binding Height, Mode=OneWay}" KeyboardNavigation.DirectionalNavigation="None" Grid.ColumnSpan="6" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" GridLinesVisibility="None" ColumnWidth="*"
Margin="1" wpfmvvm:DataGridRowHeightBehaviour.AutoFitRowHeight="True" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<DataGrid.Columns>
<DataGridTemplateColumn HeaderTemplate="{x:Null}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Label x:Name="PART_Content" Content="{Binding Path=Left.Content}"
HorizontalAlignment="Center" VerticalAlignment="Center"
Foreground="Gold"/>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=IsMonochrome}" Value="True">
<Setter TargetName="PART_Content" Property="Foreground" Value="Green"/>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
...
<DataTemplate>
The binding of the Value works because the color gets the default value of Left.Color of <Setter Property="Foreground" Value="{Binding Path=Left.Color}"/>
The IsMonochrome property changes value when a specific event occurs, but the Foreground color does not change to green. I am not quite sure the format and the structure is appropriate. I am not sure if <DataTemplate> is a problem, since I have another <DataTemplate> in higher order
The classes:
public partial class ToneAudiogramLegendTableViewModel : ViewModelBase, IToneAudiogramLegendTableViewModel, IHandleMonochromeReportElement
{
public bool IsMonochrome
{
get { return GetValue<bool>("IsMonochrome"); }
private set { SetValue("IsMonochrome", value); }
}
public void SwitchToMonochromeMode()
{
IsMonochrome = true;
}
public void SwitchToColorMode()
{
IsMonochrome = false;
}
}
and
public class ToneAudiogramLegendViewModel : ViewModelBase, IToneAudiogramLegendVM
{
public string Name
{
get { return GetValue<string>("Name"); }
set { SetValue("Name", value); }
}
public LegendViewModel Left
{
get { return GetValue<LegendViewModel>("Left"); }
set { SetValue("Left", value); }
}
}
and
public class LegendViewModel : ViewModelBase
{
public object Content
{
get { return GetValue<object>("Content"); }
set { SetValue("Content", value); }
}
public Brush Color
{
get { return GetValue<Brush>("Color"); }
set { SetValue("Color", value); }
}
public LegendViewModel(object content, Brush color)
{
Content = content;
Color = color;
}
}
What might be the issue?
In your CellTemplate you are binding to ToneAudiogramLegendViewModel object, where are properties Name and Left. The IsMonochrome is on different object, that's why it does not work.
You need to either define IsMonochrome property or you need create property to reference ToneAudiogramLegendTableViewModel in ToneAudiogramLegendViewModel to be able to databind to IsMonochrome.
EDIT:
based on your comments:
<DataTrigger Binding="{Binding Path=DataContext.IsMonochrome,
RelativeSource={RelativeSource DataGrid}}"
Value="True">
Related
I use a combobox and I would like to proceed as follows:
I choose an element in cmb1, this allows to display in cmb2 a Collection.
This code allows me to retrieve the data I want ( result A = ObservableCollectionA, result B = ObservableCollection B...)
<ComboBox Name="cmbResultatListe"
Margin="0,10,0,10"
Grid.Row="4"
Grid.Column="2"
Height="25"
Width="250" >
<ComboBox.Style>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Sections}"></Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedChoiceList}" Value="Etablissement">
<Setter Property="ItemsSource" Value="{Binding Etablissements}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding SelectedChoiceList}" Value="Service">
<Setter Property="ItemsSource" Value="{Binding Services}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ComboBox.Style>
</ComboBox>
I would now like to divide my combobox into three grids, so that I can proceed as follows:
If result A is selected => cmb2 grid0 = ObservableCollectionA.ID, cmb2 grid1 = observableCollectionA.Name...
If result B is selected => cmb2 grid0 = ObservableCollectionB.Name, cmb2 grid1 = observableCollectionB.Years...
And i don't know how can i do that.
Any tips ?
Thank you for your help.
Edit :
c# code :
private ObservableCollection<Etablissement> _EtablissementsUtilisateur;
public ObservableCollection<Etablissement> EtablissementsUtilisateur
{
get
{
return _EtablissementsUtilisateur;
}
set
{
if (value != _EtablissementsUtilisateur)
{
_EtablissementsUtilisateur = value;
RaisePropertyChanged(nameof(EtablissementsUtilisateur));
}
}
}
private ObservableCollection<ServiceSectionModel> _Services;
public ObservableCollection<ServiceSectionModel> Services
{
get
{
return _Services;
}
set
{
if (value != _Services)
{
_Services = value;
RaisePropertyChanged(nameof(Services));
}
}
}
private ObservableCollection<ServiceSectionModel> _Sections;
public ObservableCollection<ServiceSectionModel> Sections
{
get
{
return _Sections;
}
set
{
if (value != _Sections)
{
_Sections = value;
RaisePropertyChanged(nameof(Sections));
}
}
}
private string _SelectedChoiceList;
public string SelectedChoiceList
{
get
{
return _SelectedChoiceList;
}
set
{
if (value != _SelectedChoiceList)
{
_SelectedChoiceList = value;
RaisePropertyChanged(nameof(SelectedChoiceList));
}
}
}
Etablissements = new ObservableCollection<Etablissement>((await _dataService.GetEtablissements().ConfigureAwait(false)));
Services = await _dataService.GetServicesAsync(false).ConfigureAwait(false);
Sections = await _dataService.GetSectionsAsync(_dataService.ParamGlobaux.IDEtablissement).ConfigureAwait(false);
Etablissement contain ID, Name, Years.
Service contain Color, ID, Name.
Section contain Color, ID, SectionName.
Edit 2 : I would like something like this exemple :
<ComboBox Name="CbService" HorizontalAlignment="Left" Margin="115,67,0,0" VerticalAlignment="Top" Width="150" ItemsSource="{Binding}" SelectionChanged="CbRecherche_SelectionChanged" KeyboardNavigation.TabIndex="1" >
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Libelle}" />
</DataTemplate>
</ComboBox.ItemTemplate>
<ComboBox.ItemContainerStyle>
<Style TargetType="{x:Type ComboBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid x:Name="gd" TextElement.Foreground="Black" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="Auto" MinWidth="50" />
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Rectangle Fill="{Binding Fond}" Grid.Column="0"/>
<TextBlock Margin="5" Grid.Column="0" Text="{Binding ID}"/>
<TextBlock Margin="5" Grid.Column="1" Text="{Binding Libelle}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ComboBox.ItemContainerStyle>
Currently my combobox displays a string. I want something like this :
In this example, there is an ID, a color only in the ID part, and a Name. I can't do that with my string at the moment.
I belive you may be able to reduce the size of your codes by removing the RaisePropertyChanged event as ObservableCollections already contain the INotifyPropertyChanged interface, I have made a simple example of how to use Datatemplate to display information from ObservableCollections.
Step 1: C# codes:
namespace WpfApp1
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
ComboBox1.ItemsSource = Services;
Services.Add(new ServiceSectionModel { Color = Brushes.Red, ID = "Clem", Name = "Clementine" });
Services.Add(new ServiceSectionModel { Color = Brushes.White, ID = "011", Name = "Logistique" });
Services.Add(new ServiceSectionModel { Color = Brushes.Green, ID = "MBT", Name = "Montbrilland" });
}
public class ServiceSectionModel
{
public string ID { get; set; }
public string Name { get; set; }
public SolidColorBrush Color { get; set; }
}
ObservableCollection<ServiceSectionModel> Services = new ObservableCollection<ServiceSectionModel>();
}
}
Step 2: XAML codes:
<ComboBox x:Name="ComboBox1" HorizontalAlignment="Center" VerticalAlignment="Center">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Background="{Binding Color}" Text="{Binding ID}" Margin="0,0,10,0" Padding="5,2,10,2"></TextBlock>
<TextBlock Text="{Binding Name}"></TextBlock>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
I want to bind 'Units' property of ResultModel Class to DataGridComboBoxColumn. Other Bindings work fine but it cannot resolve 'Units' property. It recommends me 'Results' List instead of 'Units'. I want to use different Lists in each row.
You can see my View, ViewModel and Model Classes below.
View.xaml
<DataGrid x:Name="DataGrid" AutoGenerateColumns="False" Grid.Row="1" ItemsSource="{Binding Results}">
<DataGrid.Columns>
<DataGridTextColumn Header="#" Width="20" Binding="{Binding Path=Count}" />
<DataGridTextColumn Header="Name" Width="*" Binding="{Binding Path=ComponentName}" />
<DataGridTextColumn Header="Variable" Width="*" Binding="{Binding Path=Property}" />
<DataGridTextColumn Header="Value" Width="*" Binding="{Binding Path=PropertyValue}" />
<DataGridComboBoxColumn Header="Unit" Width="*" ItemsSource="{Binding Units}"/>
</DataGrid.Columns>
</DataGrid>
ViewModel.cs
private List<ResultModel> _results;
public List<ResultModel> Results
{
get { return _results; }
set
{
_results = value;
RaisePropertyChanged("Results");
}
}
ResultModel.cs
private int _count;
public int Count
{
get { return _count; }
set { _count = value; RaisePropertyChanged("Count"); }
}
private string _componentName;
public string ComponentName
{
get { return _componentName; }
set { _componentName = value; RaisePropertyChanged("ComponentName"); }
}
private string _property;
public string Property
{
get { return _property; }
set { _property = value; RaisePropertyChanged("Property"); }
}
private double _propertyValue;
public double PropertyValue
{
get { return _propertyValue; }
set { _propertyValue = value; RaisePropertyChanged("PropertyValue"); }
}
private List<object> _units;
public List<object> Units
{
get { return _units; }
set { _units = value; RaisePropertyChanged("Units"); }
}
private Type _componentType;
public Type ComponentType
{
get { return _componentType; }
set { _componentType = value; RaisePropertyChanged("ComponentType"); }
}
I had to use a DataGridTemplateColumn that contained a ComboBox to get it to work properly. This assumes the object in Units has a Name property to display, you should adjust DisplayMemberPath accordingly. You will pribably also want to bind SelectedItem to something, so you know what item they picked.
<DataGridTemplateColumn Header="Unit">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate DataType="local:ResultModel">
<ComboBox
DisplayMemberPath="Name"
ItemsSource="{Binding Path=Units}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Try this:
<DataGridComboBoxColumn Header="Unit" Width="*">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Units}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="ComboBox">
<Setter Property="ItemsSource" Value="{Binding Units}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
You may also want to set the DisplayMemberPath property of the DataGridComboBoxColumn to the name of a property of the units.
I'm trying to dynamically hide elements in my ComboBox based on a boolean flag in the objects bound it it but I can't seem to get it working
Here is me XAML
<xctk:CheckComboBox Name="TagsDropDown" HorizontalAlignment="Left" Height="30" Margin="0,0,0,0" VerticalAlignment="Top" Width="450" IsEditable="True" IsTextSearchEnabled="True" ItemsSource="{Binding AllTags}" ItemSelectionChanged="TagsDropDown_OnItemSelectionChanged">
<xctk:CheckComboBox.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Stretch">
<TextBlock Margin="2" Text="{Binding Name}"/>
<TextBlock Margin="2" HorizontalAlignment="Right" Text="{Binding Count}"/>
</Grid>
</DataTemplate>
</xctk:CheckComboBox.ItemTemplate>
<xctk:CheckComboBox.ItemContainerStyle>
<Style TargetType="xctk:SelectorItem">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<!-- <DataTrigger steamTools:TriggerTracing.TriggerName="is zero" steamTools:TriggerTracing.TraceEnabled="True" Binding="{Binding Path=IsZero, RelativeSource={RelativeSource Self} }" Value="True">-->
<DataTrigger Binding="{Binding Path=IsZero, RelativeSource={RelativeSource Self} }" Value="True">
<DataTrigger.Setters>
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger.Setters>
</DataTrigger>
</Style.Triggers>
</Style>
</xctk:CheckComboBox.ItemContainerStyle>
</xctk:CheckComboBox>
And the class bound to the control
public class CompTag : INotifyPropertyChanged
{
private int _count;
private bool _isZero;
public string Name { get; set; }
public bool IsZero
{
get { return _isZero; }
set
{
if (_isZero != value)
{
_isZero = value;
OnPropertyChanged("IsZero");
}
}
}
public int Count
{
get { return _count; }
set
{
if (_count != value)
{
_count = value;
OnPropertyChanged("Count");
}
}
}
Can anyone see what I am doing wrong?
Thanks in advance!
Does your AllTags list have isZero member?(in model )
if yes
Try This
Binding="{Binding Path=IsZero, {RelativeSource FindAncestor, AncestorType={x:Type xctk:CheckComboBox}} }"
if no, and it in your datacontext class try to remove RelativeSource={RelativeSource Self}
I have 3 columns . One with check box , One with text column and one column with drop down.
I am binding the entire table itemsource to StepTaskViewInfo.CurrentStep.ProjectTasks.Items . StepTaskViewInfo is a variable in my VM and others are nested in it. This works fine .
Only thing that doesnt work is the IsReadOnly property of the FIRST Columns. Am assuming this is some issue because my items source is different and the read only property is different in terms of level of nesting from view model.
For grid :
Items Source = StepTaskViewInfo -> CurrentStep -> ProjectTasks- >Items
For read only propety of each column(which doesnt work) :
IsReadOnly="{Binding StepTaskViewInfo.AreStepsTasksReadonly
StepTaskViewInfo => AreStepsTasksReadonly
<DataGrid RowHeaderWidth="0" x:Name ="TaskDataGrid" Margin="20,0,0,0" ItemsSource="{Binding StepTaskViewInfo.CurrentStep.ProjectTasks.Items}" AutoGenerateColumns="False"
CanUserSortColumns="False" HorizontalAlignment="Left" CanUserAddRows="False" SelectionChanged="TaskRowSelectionChanged"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto"
Background="White" BorderThickness ="0"
ScrollViewer.CanContentScroll="True" Height="240">
<DataGrid.Columns>
<DataGridTemplateColumn Width ="60" HeaderStyle="{StaticResource HeaderStyle}" Header="Selected" IsReadOnly="{Binding StepTaskViewInfo.AreStepsTasksReadonly,UpdateSourceTrigger=PropertyChanged }">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center" IsChecked="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding IsTaskEnabled,UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
//Column 2
<DataGridTextColumn HeaderStyle="{StaticResource HeaderStyle}" Header="Tasks" Width ="*" Binding="{Binding Name}" IsReadOnly="True">
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="TextWrapping" Value="Wrap" />
<Setter Property="AcceptsReturn" Value="true" />
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
//Column 3
<DataGridTemplateColumn HeaderStyle="{StaticResource HeaderStyle}" Header="Status" Width ="130">
<DataGridTemplateColumn.HeaderTemplate >
<DataTemplate>
<StackPanel Orientation="Horizontal" Width="130">
<Label Content ="Status" HorizontalAlignment="Left" Margin ="0,0,0,0"/>
<ComboBox Name ="DefaultStatusComboBox" ItemsSource="{StaticResource Status}" Width="86" DropDownClosed="DefaultStatusComboBox_DropDownClosed" />
</StackPanel>
</DataTemplate>
</DataGridTemplateColumn.HeaderTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox SelectedItem="{Binding Status, UpdateSourceTrigger=PropertyChanged}" Height ="26" VerticalAlignment="Top" IsReadOnly ="{Binding StatusIsReadOnly}"
IsEnabled ="{Binding IsSelected}" ItemsSource="{StaticResource Status}"/>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
view model:
public class StepTaskViewModel : INavigationAware, INotifyPropertyChanged
{
private readonly IProjectWorkflowService projectWorkflowService;
private bool isVisible = true;
private readonly IUserService userService;
private string stageId;
private StepTaskViewInfo stepTaskViewInfo;
public StepTaskViewModel(IProjectWorkflowService projectWorkflowService, IUserService userService)
{
this.projectWorkflowService = projectWorkflowService;
this.userService = userService;
StepTaskViewInfo=new StepTaskViewInfo();
}
public StepTaskViewInfo StepTaskViewInfo
{
get { return stepTaskViewInfo; }
set
{
stepTaskViewInfo = value;
OnPropertyChanged();
}
}
// set current step - >load tasks - > set display names for each task --> set drop down source for current step
public string StageId
{
get { return stageId; }
set
{
stageId = value;
StepTaskViewInfo.PeerReview.StageId = stageId;
LoadData();
}
}
#region navigation
public void OnNavigatedTo(NavigationContext navigationContext)
{
StageId =(string) navigationContext.Parameters["StageId"] ;
IsVisible = true;
}
public bool IsNavigationTarget(NavigationContext navigationContext)
{
return true;
}
public void OnNavigatedFrom(NavigationContext navigationContext)
{
if (!IsVisible)
return;
IsVisible = false;
}
public bool IsVisible
{
get { return isVisible; }
set
{
isVisible = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = "" )
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
// called when stage id changes
public void LoadData()
{
var stepTaskViewInfo = projectWorkflowService.LoadProjectStepTaskInfo(StageId);
if (StepTaskViewInfo.CurrentStep != null)
{
StepTaskViewInfo.CurrentStep.ProjectTasks.Items.Clear();
}
StepTaskViewInfo.AllTeamMembers = stepTaskViewInfo.AllTeamMembers;
StepTaskViewInfo.ProjectSteps = stepTaskViewInfo.ProjectSteps;
StepTaskViewInfo.PeerReview = stepTaskViewInfo.PeerReview;
StepTaskViewInfo.AreStepsTasksReadonly = stepTaskViewInfo.AreStepsTasksReadonly;
StepTaskViewInfo.PeerReview.Documents.Items.Add(new ActivityArtifact { FileName = string.Empty });
}
private string GetAliases(ObservableCollection<SelectableTeamMember> selectedStepMembers)
{
string aliases= selectedStepMembers.Aggregate("", (current, member) => current + (member.Alias + ";"));
aliases= aliases.TrimEnd(';');
return aliases;
}
private string GetDisplayNames(ObservableCollection<SelectableTeamMember> selectedStepMembers)
{
string names = selectedStepMembers.Aggregate("", (current, member) => current + (member.Name + ";"));
names= names.TrimEnd(';');
return names;
}
public void AssignResourcesToStep(ObservableCollection<SelectableTeamMember> selectedStepMembers)
{
StepTaskViewInfo.CurrentStep.StepTeamMembers = selectedStepMembers;
StepTaskViewInfo.CurrentStep.Resources = GetAliases(selectedStepMembers);
StepTaskViewInfo.CurrentStep.StepResourceDisplayName = GetDisplayNames(selectedStepMembers);
foreach (var task in StepTaskViewInfo.CurrentStep.ProjectTasks)
{
task.AllTaskTeamMembers = StepTaskViewInfo.CurrentStep.StepTeamMembers;
task.Resources = GetAliases(StepTaskViewInfo.CurrentStep.StepTeamMembers);
task.TaskResourceDisplayName = GetDisplayNames(StepTaskViewInfo.CurrentStep.StepTeamMembers);
}
}
public void AssignResourcesToTask(ObservableCollection<SelectableTeamMember> selectedTaskMembers, string taskId)
{
var task = StepTaskViewInfo.CurrentStep.ProjectTasks.First(st => st.Id == taskId);
task.Resources = GetAliases(selectedTaskMembers);
task.TaskResourceDisplayName = GetDisplayNames(selectedTaskMembers);
}
public void AssignTaskTips(string ttid)
{
string taskTip = projectWorkflowService.GetTaskTip(ttid);
foreach (var task in StepTaskViewInfo.CurrentStep.ProjectTasks)
{
if (task.TemplateTaskId == ttid)
task.TaskTip = taskTip;
}
}
#region peerreview
public void DownloadDocument(string artifactId, string fileName)
{
projectWorkflowService.DownloadActivityArtifact(artifactId, fileName);
}
public void UploadDocument(string artifactId,string file)
{
projectWorkflowService.UploadActivityArtifact(StageId, artifactId, file);
var projectDocuments = projectWorkflowService.LoadPeerReviewDocuments(StageId);
projectDocuments.Items.Add(new ActivityArtifact { FileName = string.Empty });
StepTaskViewInfo.PeerReview.Documents = projectDocuments;
}
private void GetUsers()
{
foreach (ProjectPeerReview t in StepTaskViewInfo.PeerReview.Reviews.Items.ToList())
{
if (string.IsNullOrEmpty(t.Id))
{
if (!string.IsNullOrEmpty(t.Alias))
{
User current = userService.SearchAlias(t.Alias);
if (current == null)
{
MessageBox.Show("Could not find reviewer " + t.Alias);
StepTaskViewInfo.PeerReview.Reviews.Items.Remove(t);
}
else
{
t.Name = current.Name;
}
}
}
}
}
internal User[] GetSearchingUsersName(string name)
{
return userService.Search(name);
}
#endregion
public void UpdateTaskStatus(object selectedValue)
{
foreach (var task in StepTaskViewInfo.CurrentStep.ProjectTasks)
{
task.Status = selectedValue.ToString();
}
}
public void LoadTasksForCurrentStep()
{
StepTaskViewInfo.CurrentStep.ProjectTasks = projectWorkflowService.LoadProjectTasks( StepTaskViewInfo.CurrentStep.Id);
StepTaskViewInfo.UpdateTaskResources();
}
public void SaveCurrentTasksWithStep()
{
if (StepTaskViewInfo.CurrentStep != null)
{
projectWorkflowService.SaveTasksWithStep(StageId, StepTaskViewInfo.CurrentStep, StepTaskViewInfo.CurrentStep.ProjectTasks);
}
}
public bool SaveData()
{
if (StepTaskViewInfo.CurrentStep != null)
{
GetUsers();
return projectWorkflowService.SaveStepTaskViewInfo(StepTaskViewInfo, StageId);
}
return true;
}
}
}
DataGridColumn.IsReadOnly property will make all cells in the column either ReadOnly or not ReadOnly. DataGridCell.IsReadOnly property is not assignable too. What you are trying to do is to make a column readonly if some other property is false, else column should be editable. It is better to use a template column and set the control accordingly. MSDN
For example, if I want user to edit CarNumber property value is HasCar property value is true else not, then if I write :
<DataGridTextColumn Header="CarNumber" Binding="{Binding CarNumber}" IsReadOnly="{Binding HasCar"/>
//
This will still allow all column values to be editable irrespective of HasCar value.
//
If I use Template column and use DataTrigger then I get the desired effect. This wont allow user to type/edit CarNumber if HasCar property is false :
<DataGridTemplateColumn Header="CarNumber" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBox x:Name="TxtCarNumber" Text="{Binding CarNumber}" >
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding HasCar}" Value="False">
<Setter Property="TextBox.Visibility" Value="Hidden"/>
<Setter Property="TextBox.Width" Value="100"/>
</DataTrigger>
<DataTrigger Binding="{Binding HasCar}" Value="True">
<Setter Property="TextBox.Visibility" Value="Visible"/>
<Setter Property="TextBox.Background" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
In your code do this, as you want your CheckBox to remain visible but not enabled :
<DataGridTemplateColumn Width ="60" HeaderStyle="{StaticResource HeaderStyle}" Header="Selected" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid IsEnabled={Binding StepTaskViewInfo.AreStepsTasksReadonly}>
<CheckBox VerticalAlignment="Center" HorizontalAlignment="Center"
IsChecked="{Binding IsSelected,UpdateSourceTrigger=PropertyChanged}"
IsEnabled="{Binding IsTaskEnabled,UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
I'm trying to show collection of bool with a DataTemplate for ListView.
Here's the code:
In MainWindow.xaml
<Window.Resources>
<DataTemplate x:Key="ListItemCheckBoxTemplate">
<CheckBox IsChecked="{Binding Mode=OneWay}"/>
</DataTemplate>
<DataTemplate x:Key="ListItemRadioButtonTemplate">
<RadioButton IsChecked="{Binding Mode=OneWay}"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="120"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Text="ListViewSample" />
<ListBox ItemsSource="{Binding MyData}" ItemTemplate="{StaticResource ListItemCheckBoxTemplate}" Grid.Column="1"/>
</Grid>
In MainWindow.xaml.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
}
public class ViewModel
{
private List<bool> myBooleanCollection;
public List<bool> MyData
{
get { return myBooleanCollection; }
set { myBooleanCollection = value; }
}
public ViewModel()
{
myBooleanCollection = new List<bool>();
myBooleanCollection.Add(true);
myBooleanCollection.Add(false);
myBooleanCollection.Add(true);
myBooleanCollection.Add(true);
myBooleanCollection.Add(false);
}
}
Instead of ItemTemplate ListItemCheckBoxTemplate I want to apply ListItemRadioButtonTemplate with Radio button. How I can specify the use of ItemTemplate for the same source in xaml. Do I need to change the DataSource for the same or
do I have some way to specify the DataTemplate in xaml based on condition.
You did not specify what is the condition on which you want to change template but you can add another property to your view model, say AllowMultiple:
public class ViewModel: INotifyPropertyChanged
{
private List<bool> myBooleanCollection;
public List<bool> MyData
{
get { return myBooleanCollection; }
set { myBooleanCollection = value; }
}
private bool _allowMultiple;
public bool AllowMultiple
{
get { return _allowMultiple; }
set
{
if (_allowMultiple != value)
{
_allowMultiple = value;
OnPropertyChanged("AllowMultiple");
}
}
}
}
and then change ListBox.Style to:
<ListBox ItemsSource="{Binding MyData}">
<ListBox.Style>
<Style TargetType="{x:Type ListBox}">
<Setter Property="ItemTemplate" Value="{StaticResource ListItemCheckBoxTemplate}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding Path=AllowMultiple}" Value="False">
<Setter Property="ItemTemplate" Value="{StaticResource ListItemRadioButtonTemplate}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</ListBox.Style>
</ListBox>
assuming that ViewModel implements INotifyPropertyChanged you can then change ItemTemplate buy changing AllowMultiple against view model
You can specify DataTemplate for each item with the followign attribute:
ItemTemplate="{StaticResource ListItemCheckBoxTemplate}
Change this to:
ItemTemplate="{StaticResource ListItemRadioButtonTemplate}
If you need multiple item templates in the same ListBox then you can provide custom template selection logic via the DataTemplateSelector Class
If you want to do it in Xaml, you will need to expose property which you can bind to as a selector. Have a look at A Data Template Selector in Xaml
You need create DataTemplateSelector and using this for ItemTemplateSelector. You also need to determine the condition under which you will return the DataTemplate. Example:
XAML
<Window x:Class="YourNamespace.MainWindow" ...
xmlns:this="clr-namespace:YourNamespace"
<Window.Resources>
<DataTemplate x:Key="OneTemplate">
<CheckBox IsChecked="{Binding Mode=OneWay}" />
</DataTemplate>
<DataTemplate x:Key="SecondTemplate">
<RadioButton IsChecked="{Binding Mode=OneWay}" />
</DataTemplate>
</Window.Resources>
<ListBox ItemsSource="{Binding MyData}">
<ListBox.ItemTemplateSelector>
<this:MyItemTemplateSelector OneTemplate="{StaticResource OneTemplate}"
SecondTemplate="{StaticResource SecondTemplate}" />
</ListBox.ItemTemplateSelector>
</ListBox>
Code-behind
public class MyItemTemplateSelector : DataTemplateSelector
{
public DataTemplate OneTemplate { get; set; }
public DataTemplate SecondTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
bool myItem = (bool)item;
if (myItem == true)
{
return OneTemplate;
}
return SecondTemplate;
}
}