|
That is clear, because you are not telling the WPF to actually write the Description to the rendering; as I believe, it is just trying to call a simple ToString and then writing what is found there.
For this thread, it is pretty much clear that what you need to do is you need to create a converter for your binding and then read the DescriptionAttribute of the current enum value. Then render that Description in the returning object. You might need to implement the converter, and then add that as an object.
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
I'm trying to extend the WPF dataGrid so I can bind to SelectedItems when SelectionMode = Extended.
First I have this
public class DataGridEx : DataGrid
{
public DataGridEx()
{
this.SelectionChanged += CustomDataGrid_SelectionChanged;
}
public IList SelectedItemsList
{
get { return (IList)GetValue(SelectedItemsListProperty); }
set { SetValue(SelectedItemsListProperty, value); }
}
public static readonly DependencyProperty SelectedItemsListProperty =
DependencyProperty.Register("SelectedItemsList", typeof(IList), typeof(DataGridEx), new PropertyMetadata(null));
private void CustomDataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
this.SelectedItemsList = this.SelectedItems;
}
}
Then my XAML
<ctrls:DataGridEx x:Name="_ScenariosTable"
Grid.Column="1"
Grid.Row="6"
SelectionMode="Extended"
ItemsSource="{Binding Scenarios}"
SelectedItemsList="{Binding SelectedScenarios, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
and finally my View Model
private List<Scenario> _SelectedScenarios;
public List<Scenario> SelectedScenarios
{
get { return _SelectedScenarios; }
set
{
if (_SelectedScenarios != value)
{
_SelectedScenarios = value;
RaisePropertyChanged("SelectedScenarios");
}
}
}
The binding works because the SETTER is called, yet 'value' is always null.
What's wrong here?
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
According to the comments on this StackOverflow answer[^], it should work if you use IList instead of IList<T> in your viewmodel.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
That did it! Thanks!
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
I have this combo box:
<ComboBox Grid.Row="1"
Grid.Column="0"
ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedRight.Category}"
IsEnabled="{Binding RightsFieldsEnabled}"
Width="250"
Margin="2"
Style="{StaticResource comboBoxStyle}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Category}"
FontSize="14"/>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
When a Category is selected is saves it correctly to the Category property of the Right entity. However, when the data is reloaded the correct Category is not selected in the combo.
What am I doing wrong here?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Chances are that your objects and lists are (some sort of) based on the instance properties or fields of the object that is bound. Did you try any static fields here (try making the data source static and then see if that has any effect on reload)?
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
SelectedItem,mode="twoway"
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
No effect
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
You are trying to bind the item attribute to the selected item. Change it to display value and selected item id. Sorry I am on a pad with no vs.
Never underestimate the power of human stupidity
RAH
|
|
|
|
|
My enum:
public enum AccessLevel
{
[Description("No Acccess")]
NoAccess = 0,
[Description("Full Acccess")]
HasAccess = 1
}
My Right entity
public class RightEntity : _EntityBase
{
private string _RightName = string.Empty;
public string RightName
{
get { return _RightName; }
set
{
if (_RightName != value)
{
_RightName = value;
RaisePropertyChanged("RightName");
}
}
}
private AccessLevel _Access = AccessLevel.NoAccess;
public AccessLevel Access
{
get { return _Access; }
set
{
if (_Access != value)
{
_Access = value;
RaisePropertyChanged("Access");
}
}
}
}
The view
<Window.Resources>
<wpfconv:EnumDescriptionConverter x:Key="EnumDescriptionConverter" />
<ObjectDataProvider MethodName="GetValues"
ObjectType="{x:Type sys:Enum}"
x:Key="accessEnums">
<ObjectDataProvider.MethodParameters>
<x:Type TypeName="enums:AccessLevel" />
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
</Window.Resources>
and
<ComboBox Grid.Row="7"
Grid.Column="0"
ItemsSource="{Binding Source={StaticResource accessEnums}}"
SelectedItem="{Binding SelectedRight.Access}"
IsEnabled="{Binding RightsFieldsEnabled}"
Width="125"
HorizontalAlignment="Left"
Style="{StaticResource comboBoxStyle}"
Margin="2">
<pre>
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Converter={StaticResource EnumDescriptionConverter}}"
FontSize="14"/>
</DataTemplate>
</ComboBox.ItemTemplate>
Problem: When I load the combo list the enum descriptions show fine. I then edit a record and save, then reload the list. I then get an exception in the converter in the Convert method:
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
Enum myEnum = (Enum)value;
string description = GetEnumDescription(myEnum);
return description;
}
Not really sure what's happening. Am I doing this right? Anyone see what's wrong?
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Can you try the following code and see if this works?
object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(string.IsNullOrEmpty(value as string)) {
Enum myEnum = (Enum)value;
string description = GetEnumDescription(myEnum);
return description;
} else {
}
}
The sh*t I complain about
It's like there ain't a cloud in the sky and it's raining out - Eminem
~! Firewall !~
|
|
|
|
|
Actually, I already did that and it seems to work ok.
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Hello,
I am trying to make an app to schedule real life tasks. My main purpose is to learn how to switch between views with commands. Switching between views has partially worked.
My "app" has a main window, with a few buttons(like a horizontal menu bar), and a content control area below the menu buttons, where i display views associated with the buttons.
I managed somehow to make the buttons to switch to my views.
My first 2 views are the "HomeView" and "AddEditView".
In my HomeView i have a listview that is displaying the tasks from my database. On my listview i have attached a contextmenu with 3 options/buttons: Add Task, Edit Task, Remove Task.
I want o make the contextmenu options/buttons to take me to the AddEditView so i can Add/Edit my selected task.
I have tried to bind the contextmenu buttons to the main window buttons and commands, but most likely i did something wrong. I have also tried to link my HomeViewModel with the MainWindowViewModel , but when i am newing up a MainWindowViewModel object in my HomeViewModel i get the following error
An unhandled exception of type 'System.StackOverflowException' occurred in mscorlib.dll
pointing to
public TaskLINQToSQLClassesDataContext() :
base(global::DTS.Properties.Settings.Default.TasksConnectionString, mappingSource)
What should i do? Is there other piece of code i should post?
Thanks in advance!
MainWindowViewModel:
public class MainWindowViewModel : INotifyPropertyChanged
{
private HomeViewModel homeVM;
private AddEditViewModel addEditVM;
private NotesViewModel notesVM;
private StatsViewModel statsVM;
private object currentView;
public SwitchViewCommand SwitchToHomeViewCommand { get; private set; }
public SwitchViewCommand SwitchToAddEditViewCommand { get; private set; }
public SwitchViewCommand SwitchToNotesViewCommand { get; private set; }
public SwitchViewCommand SwitchToStatsViewCommand { get; private set; }
public MainWindowViewModel()
{
homeVM = new HomeViewModel();
addEditVM = new AddEditViewModel();
notesVM = new NotesViewModel();
statsVM = new StatsViewModel();
SwitchToHomeViewCommand = new SwitchViewCommand(DisplayHomeView);
SwitchToAddEditViewCommand = new SwitchViewCommand(DisplayAddEditView);
SwitchToNotesViewCommand = new SwitchViewCommand(DisplayNotesView);
SwitchToStatsViewCommand = new SwitchViewCommand(DisplayStatsView);
CurrentView = homeVM;
}
public object CurrentView
{
get { return currentView; }
set { currentView = value; RaisePropertyChanged(); }
}
public void DisplayHomeView()
{
CurrentView = homeVM;
}
public void DisplayAddEditView()
{
CurrentView = addEditVM;
}
public void DisplayNotesView()
{
CurrentView = notesVM;
}
public void DisplayStatsView()
{
CurrentView = statsVM;
}
#region INPC
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
var hndlr = PropertyChanged;
if (hndlr != null)
{
hndlr(this, new PropertyChangedEventArgs(propertyName));
}
}
#endregion
}
HomeViewModel:
public class HomeViewModel : BaseViewModel
{
private Models.Task selectedTask;
private string isCompleted;
private ObservableCollection<Models.Task> taskList;
public HomeViewModel()
{
TaskList = new ObservableCollection<Models.Task>(tDC.Tasks);
MwVm = new MainWindowViewModel();
}
public MainWindowViewModel MwVm { get; set; }
public Models.Task SelectedTask
{
get { return selectedTask; }
set
{
if (selectedTask!=value)
{
selectedTask = value;
RaisePropertyChanged();
IsCompleted = selectedTask.Completed == true ? "Completed" : "Not Completed";
}
}
}
public string IsCompleted
{
get { return isCompleted; }
set
{
isCompleted = value;
RaisePropertyChanged();
}
}
public ObservableCollection<Models.Task> TaskList
{
get { return taskList; }
set
{
if (taskList != value)
{
taskList = value;
RaisePropertyChanged();
}
}
}
public void ViewChange()
{
MwVm.SwitchToAddEditViewCommand.Execute(this);
}
}
MainWindowView buttin bindings and conent control:
<StackPanel Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="8" Grid.RowSpan="1" Orientation="Horizontal" HorizontalAlignment="Center" >
<Button x:Name="btnHome" Style="{StaticResource MenuButton}" Content="Home" Grid.Column="1" Grid.ColumnSpan="2" Width="73" Command="{Binding SwitchToHomeViewCommand}">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DodgerBlue" Offset="0.777"/>
<GradientStop Color="#FF9BCF31" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
<Button x:Name="btnAddEdit" Style="{StaticResource MenuButton}" Content="Add/Edit" Grid.Column="2" Grid.ColumnSpan="2" Width="73" Command="{Binding SwitchToAddEditViewCommand}">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DodgerBlue" Offset="0.777"/>
<GradientStop Color="#FF9BCF31" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
<Button x:Name="btnNotes" Style="{StaticResource MenuButton}" Content="Notes" Grid.Column="4" Grid.ColumnSpan="2" Width="73" Command="{Binding SwitchToNotesViewCommand}">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DodgerBlue" Offset="0.777"/>
<GradientStop Color="#FF9BCF31" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
<Button x:Name="btnSettings" Style="{StaticResource MenuButton}" Content="Settings" Grid.Column="6" Grid.ColumnSpan="2" Width="73" Command="{Binding SwitchToStatsViewCommand}">
<Button.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="DodgerBlue" Offset="0.777"/>
<GradientStop Color="#FF9BCF31" Offset="1"/>
</LinearGradientBrush>
</Button.Background>
</Button>
</StackPanel>
<ContentControl Grid.Column="0" Grid.ColumnSpan="8" Grid.Row="2" Grid.RowSpan="6" Content="{Binding CurrentView}" HorizontalAlignment="Center" VerticalAlignment="Stretch"/>
HomeView :
<UserControl x:Class="DTS.Views.HomeView"
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"
xmlns:local="clr-namespace:DTS.Views"
mc:Ignorable="d" d:DesignWidth="400" Height="220">
<Grid Margin="0,0,0,-6">
<TextBlock Style="{StaticResource ListviewTitleTxtBlock}" Text="Task List" Margin="10,10,184,196" />
<ListView x:Name="LstVviewTaskList" Height="181" Width="120" Margin="10,35,270,0" VerticalAlignment="Top" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" ItemsSource="{Binding TaskList}" SelectedItem="{Binding SelectedTask,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add Task" Background="AliceBlue" Command="{Binding HomeViewModel.SwitchViewAddEditCmd}"/>
<MenuItem Header="Edit Task" Background="AliceBlue" Command="{Binding HomeViewModel.SwitchViewAddEditCmd}"/>
<MenuItem Header="Remove Task" Background="AliceBlue" Command="{Binding HomeViewModel.SwitchViewAddEditCmd}"/>
</ContextMenu>
</ListView.ContextMenu>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=TaskTitle}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<TextBox Height="20" Margin="140,35,10,171" IsReadOnly="True" Text="{Binding ElementName=LstVviewTaskList, Path=SelectedItem.TaskTitle}"/>
<TextBox Margin="140,61,10,80" IsReadOnly="True" Text="{Binding ElementName=LstVviewTaskList, Path=SelectedItem.TaskDescripion}" />
<Button Content="Mark as completed" FontSize="10" Margin="140,172,13,31" Command="{Binding SwitchViewAddEditCmd}"/>
<TextBlock FontSize="12" Foreground="Black" TextAlignment="Center" Text="{Binding IsCompleted, FallbackValue='Task Completion'}" Margin="140,200,13,10" />
<TextBlock FontSize="12" TextAlignment="Center" Text="{Binding ElementName=LstVviewTaskList, Path=SelectedItem.TaskDate, FallbackValue='Task Date'}" Margin="143,151,10,59" />
</Grid>
</UserControl>
|
|
|
|
|
So, your architecture here has your ViewModels creating instances of each other in the constructor. This is why you are getting a stack overflow. If I were writing this, I would have a parent ViewModel that was responsible for creating this child ViewModels, and use that one to choose which VM was current.
This space for rent
|
|
|
|
|
I will try this.
Thank you!
|
|
|
|
|
Member 12880595 wrote: public MainWindowViewModel()
{
homeVM = new HomeViewModel();
Member 12880595 wrote: public HomeViewModel()
{
...
MwVm = new MainWindowViewModel();
So MainWindowViewModel creates a new HomeViewModel , which creates a new MainWindowViewModel , which creates a new HomeViewModel , which creates...
A classic case of infinite recursion.
Change your code to pass the current MainWindowViewModel instance to each of the child viewmodels:
public MainWindowViewModel()
{
homeVM = new HomeViewModel(this);
addEditVM = new AddEditViewModel(this);
notesVM = new NotesViewModel(this);
statsVM = new StatsViewModel(this);
...
}
...
public HomeViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
...
public AddEditViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
...
public NotesViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
...
public StatsViewModel(MainWindowViewModel mwVm)
{
MwVm = mwVm;
...
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank you, it works!
But, how can i make the view change?
Assuming i have a MainWindowViewModel property in each "lower" ViewModel class, should i bind my contextmenu buttons to it, and RaisePropertyChanged, and add a call in the setter to the method i use in the MainViewModel to Display my AddEditView?
|
|
|
|
|
The simplest option is to call the method directly, since it's public:
public void ViewChange()
{
MwVm.DisplayAddEditView();
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
I have tried, to call the method, by having a MainWindowViewModel property, and call ViewChangeMethod() in the setter, but it doesnt work;
public HomeViewModel(MainWindowViewModel mwvm)
{
TaskList = new ObservableCollection<Models.Task>(tDC.Tasks);
MwVm = mwvm;
}
public MainWindowViewModel MwVm
{
get { return _mwVm; }
set {if(value != null)
_mwVm = value;
RaisePropertyChanged();
ViewChange();
}
}
<ListView x:Name="LstVviewTaskList" Height="181" Width="120" Margin="10,35,270,0" VerticalAlignment="Top" VerticalContentAlignment="Top" HorizontalContentAlignment="Left" ItemsSource="{Binding TaskList}" SelectedItem="{Binding SelectedTask,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}">
<ListView.ContextMenu>
<ContextMenu>
<MenuItem Header="Add Task" Background="AliceBlue" Command="{Binding MwVm, UpdateSourceTrigger=PropertyChanged}"/>
<MenuItem Header="Edit Task" Background="AliceBlue" Command="{Binding MwVm, UpdateSourceTrigger=PropertyChanged}"/>
<MenuItem Header="Remove Task" Background="AliceBlue" Command="{Binding MwVm, UpdateSourceTrigger=PropertyChanged}"/>
</ContextMenu>
</ListView.ContextMenu>
What should i make sure i checked/have to check, in this case?
If i bind a contextmenu item(located in my HomeView) to a MainWindow Button, and the command associated with it, should i specify the datacontext in xaml?
|
|
|
|
|
That code makes no sense.
Firstly, when you create the new HomeViewModel , you're immediately trying to switch the view to the AddEditViewModel . Since you haven't created that viewmodel at this point, it's not going to work.
MainWindowViewModel.ctor
⇒ HomeViewModel.ctor
⇒ HomeViewModel.MwVm.set
⇒ HomeViewModel.ViewChange
⇒ MainWindowViewModel.DisplayAddEditView
Secondly, the MainWindowViewModel is not an ICommand . You can't use it as the Command property in the context menu.
Commanding Overview[^]
Introduction to WPF Commands[^]
Using WPF commands[^]
Implementing a custom WPF Command[^]
Take a step back and think about what you're trying to do.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Ok, i will try and rethink the project(or at least the view changing&commanding part).
Thank you for helping me!
|
|
|
|
|
I have a static class called AppCore. It contains a reference to the currently logged in user:
public static class AppCore
{
public static UserEntity CurrentUser { get; private set; }
public static void Login()
{
}
}
I want to to display the CurrentUser.FullName on the main widnow:
<TextBlock Text="{Binding Source={x:Static local:AppCore.CurrentUser}, Path=FullName, Mode=TwoWay}"/>
When I log in, I don't see the user's name. I suspect its because I can't implemenet I NotifyPropertyChanged in a static class.
Is there a way to do this that I'm not seeing?
Thanks
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
If you're using .NET 4.5 or higher, you can:
What's New in WPF Version 4.5 - Binding to static properties[^]
public static class AppCore
{
public static UserEntity CurrentUser { get; private set; }
public static event EventHandler CurrentUserChanged;
public static void Login()
{
CurrentUserChanged?.Invoke(null, EventArgs.Empty);
}
}
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
How does that get the UI to refresh? The event is raised, but so what? I need the bound value in the UI to update
If it's not broken, fix it until it is.
Everything makes sense in someone's mind.
Ya can't fix stupid.
|
|
|
|
|
Read the link:
The data binding engine recognizes when the property's value changes if a static event is raised.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|