How to Bind dynamic values in Xaml using WPF in c# - c#

I have created application in WPF with two window. In one window i have used with one text box and submit button. Once submit from first window i hide first window and show second window. I have taken some values using first window text value and need to bind in second window Xaml. Actually that values can bind using foreach in html(mvc) but need to bind Xaml for display in second window. Please give some suggestions.

Please find the below answer, It will work definitely
Xaml :
<ItemsControl Name="icTodoList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="200,50,0,30">
<TextBlock>
<Hyperlink TextDecorations="None" NavigateUri="{Binding UriPath}" RequestNavigate="Hyperlink_RequestNavigate"
CommandParameter="{Binding ElementName=myImg}">
<Image HorizontalAlignment="Left" Width="80" Height="80" x:Name="myImg" Source="{Binding Source}" Margin="5"/>
</Hyperlink>
</TextBlock>
<TextBlock TextAlignment="Left" Margin="200,30,0,0">
<TextBlock FontSize="22px" Text="{Binding Title}" Foreground="white"></TextBlock>
</TextBlock>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
C# code for binding Values,
public class DMScreen3 {
public List<string> AllFiles { get; set; }
List<BindingFilesContent> items = new List<BindingFilesContent>();
if(AllFiles != null)
{
foreach(var r in AllFiles)
{
if ((r.ToLower().Contains(".avi") || r.ToLower().Contains(".mp4")) && fileTypes == "video")
{
items.Add(new BindingFilesContent() { Title = Path.GetFileName(r), UriPath = r, Source = "/images/videoicon.png" });
}
icTodoList.ItemsSource = items;
}
}
}
public class BindingFilesContent
{
public string Title { get; set; }
public string Source { get; set; }
public string UriPath { get; set; }
}

Related

Changing the ViewModel's property from another ViewModel

I have the ListBox on my MainView.xaml, selecting the Item forces the ContentControl to display different UserControls. I use Caliburn.Micro library in this propgram. Here's some code:
<ListBox Grid.Row="1" Grid.Column="1" x:Name="ItemsListBox" SelectedItem="0" ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding TextBlock1Text}" x:Name="TextBlock1"/>
<ContentControl Grid.Row="3" Grid.Column="1" Content="{Binding ElementName=ItemsListBox, Path=SelectedItem.Content}" />
The MainViewModel.cs:
private string _name;
public string Name
{
get => _name;
set
{
_name = value;
NotifyOfPropertyChange(() => Name);
}
}
private string _textBlock1Text;
public string TextBlock1Text
{
get => _textBlock1Text;
set
{
_textBlock1Text = value;
NotifyOfPropertyChange(() => TextBlock1Text);
}
}
public MainViewModel()
{
TextBlock1Text = "Test";
Items = new ObservableCollection<ItemsModel>()
{
new ItemsModel { Name="Useless", Content=null },
new ItemsModel { Name="TextChangerViewModel", Content=new TextChangerViewModel(TextBlock1Text) }
};
}
public ObservableCollection<ItemsModel> Items { get; set; }
The ItemsModel.cs:
public class ItemsModel
{
public string Name { get; set; }
public object Content { get; set; }
}
And finally the TextChangerViewModel.cs:
public class TextChangerViewModel : Conductor<object>
{
private string _textBlock1Text;
public string TextBlock1Text
{
get => _textBlock1Text;
set
{
_textBlock1Text = value;
NotifyOfPropertyChange(() => TextBlock1Text);
}
}
public TextChangerViewModel(string textBlock1Text) //passing parameter from another ViewModel
{
TextBlock1Text = textBlock1Text;
}
}
So, the main question is how to change the TextBlock1Text (and the Text value of TextBlock in .xaml as well) in the MainViewModel.cs from the TextChangerViewModel.cs? I was thinking about using something like NotifyCollectionChanged on my Items ObservableCollection, but it work with collection of ItemsModel, not with the VM's, so I'm stuck here.
I'm also not sure if having public object Content { get; set; } in ItemsModel.cs is a good thing if I'm targeting the MVVM pattern, but I don't know the other way to do it (I'm very new to MVVM).
UPD
I'm looking for the property-changing way because I need to change the TextBlock1Text Text from another UserControl. Suppose I have the button on my TextChangerView.xaml: <Button Grid.Row="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Content="Change da text" cal:Message.Attach="ChangeTextButton"/>
And after the click on it I want the text on the parental MainView.xaml to change. But the thing is, I don't know how to change properties in this case, as I wrote above why.
Change the the binding of textblox1 to reference the selected item.
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding ElementName=ItemsListBox, Path=SelectedItem.Name}" x:Name="TextBlock1"/>
or
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding ElementName=ItemsListBox, Path=SelectedItem.Content.TextBlock1Text}" x:Name="TextBlock1"/>

Best approach to add an item to a databound Listbox using MVVM pattern?

I'm facing a problem in my WPF project at the moment. At this moment I have a Viewmodel which has a Manager (to communicate with the repo).
internal class TicketViewModel
{
private TicketManager mgr;
public IEnumerable<Ticket> List { get; set; }
public TicketViewModel()
{
mgr = new TicketManager();
List = mgr.GetTickets();
}
}
I've managed to bind this list to the Listbox in my MainWindow. The next step is that I need to add an extra ticket to the list and also pass this through the manager. The problem is I need two parameters from some Controls in the MainWindow. From MVVM perspective I need to use bound Commands on e.g. a Button to communicate with the viewmodel as my viewmodel can't/may not access controls from the window. Is using parameterized Commands the way to go here?
The next problem is that the Listbox won't update I guess. This is the code:
<ListBox x:Name="listboxTix" BorderThickness="0" ItemsSource="{Binding List}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Bisque" Background="Beige" BorderThickness="2">
<StackPanel Width="250">
<TextBlock Text="{Binding TicketNumber}" />
<TextBlock Text="{Binding Text}" />
<TextBlock Text="{Binding State}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
I found that using a CompareableCollection is the way to go here, but then I still have to read all the Tickets again after adding a new Ticket.
Thanks in advance,
Hicy
okay here is the code.
Lets say you have three textboxes on MainWindow(since you have three Textblocks.) so Your MainWindow.xaml looks like
<Window.DataContext>
<local:MyViewModel/>--set's your viewModel
</Window.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="250*"/>
<RowDefinition Height="90"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0" x:Name="listboxTix" BorderThickness="0" ItemsSource="{Binding List}">
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Bisque" Background="Beige" BorderThickness="2">
<StackPanel Width="250">
<TextBlock Text="{Binding TicketNumber}" />
<TextBlock Text="{Binding Text}" />
<TextBlock Text="{Binding State}" />
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<TextBox x:Name="TicketNumber" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=Text}" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="Text" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=State}" />
<TextBox x:Name="State" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Path=TicketNumber}" />
<Button Content="Button" Command="{Binding Path=MainCommand}" Grid.Row="2"/>
</Grid>
and I am assuming that you have some class called class Ticket which contain these three members
Class Ticket
{
public int TicketNumber { get; set; }
public string Text { get; set; }
public string State { get; set; }
}
Now in class TicketManager we fill it with some dummy data
class TicketManager
{
ObservableCollection<Ticket> tl = new ObservableCollection<Ticket>();
internal ObservableCollection<Ticket> GetTickets()
{
tl.Add(new Ticket() { State = "State1", Text = "Text1", TicketNumber = 1 });
tl.Add(new Ticket() { State = "State2", Text = "Text2", TicketNumber = 2 });
tl.Add(new Ticket() { State = "State3", Text = "Text3", TicketNumber = 3 });
return tl;
}
}
and in your Mainwindow ViewModel lets call it MyViewModel.cs we add
class MyViewModel:INotifyPropertyChanged
{
private TicketManager mgr;
public ObservableCollection<Ticket> List { get; set; }
private string text;
private string state;
private int ticketNumber;
private readonly DelegateCommand<object> MyButtonCommand;
public Class1()
{
mgr = new TicketManager();
List = mgr.GetTickets();
MyButtonCommand = new DelegateCommand<object>((s) => { AddListToGrid(text, state, ticketNumber); }, (s) => { return !string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(state); });
}
private void AddListToGrid(string text, string state, int ticketNumber)
{
List.Add(new Ticket() {Text=text,State=state,TicketNumber=ticketNumber });
}
public DelegateCommand<object> MainCommand
{
get
{
return MyButtonCommand;
}
}
public string Text
{
get
{
return text;
}
set
{
text = value;
OnPropertyChanged("Text");
MyButtonCommand.RaiseCanExecuteChanged();
}
}
public string State
{
get
{
return state;
}
set
{
state = value;
OnPropertyChanged("State");
MyButtonCommand.RaiseCanExecuteChanged();
}
}
public int TicketNumber
{
get
{
return ticketNumber;
}
set
{
ticketNumber = value;
OnPropertyChanged("TicketNumber");
MyButtonCommand.RaiseCanExecuteChanged();
}
}
private void OnPropertyChanged(string p)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(p));
}
public event PropertyChangedEventHandler PropertyChanged;
}
You can Modify the code in anyway you want
This ViewModel implements fewthings which are very important from MVVM point of view
1) INotifyPropertyChanged
2) WPF Delegate Command
P.S:The code is tested and it runs as expected
Don't get hung up on MVVM it is simply a separation of data from a view, and models are shared between the two with a majority of the business logic (on a shared component) should be performed on the VM; it is not a religion just a three tiered data system. IMHO
If your button needs to do an operation, have it make a call, most likely in the code behind, to a method on the VM which handles the business logic, updates the list with the new item and notifies the manager.
I would bind the list in question to an ObservableCollection which can notify upon insert/delete of an item.

windows store app(passing two fields through a command parameter) on the click of a button

I am working on a windows store app. I want to be able to pass two parameter on the click of a button to another page.
I am able to pass one conveniently like the line below
CommandParameter="{Binding CustomerServiceRepresentativeId}"
How can I pass an additional field like the one below making two fields passed to the destination page.
Binding CustomerServiceRepresentativeName
I have had no luck passing the two.
<GridView x:Name="GVCSRList" Grid.Column="2" Grid.Row="2" ItemsSource="{Binding}" SelectionMode="None" ItemContainerStyle="{StaticResource GridViewItemStyle1}" Width="Auto" Margin="40,0,0,0">
<GridView.ItemTemplate>
<DataTemplate >
<Button Style="{StaticResource CSRProfile}" Margin="0,0,10,0" Click="ButtonBase_OnClick" CommandParameter="{Binding CustomerServiceRepresentativeId}">
<StackPanel Width="290" Height="45" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="0">
<TextBlock Tag="CSRListName" Text="{Binding CustomerServiceRepresentativeName}" Style="{StaticResource CntMedTextBlockStyleBold}" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="10,15"/>
</StackPanel>
</Button>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
try
{
var commandParameter = ((Button)sender).CommandParameter;
if (commandParameter != null)
this.Frame.Navigate(typeof(CSRProfile), commandParameter.ToString());
}
catch (Exception ex)
{
throw ex;
}
}
Bind to a new property that has both memebers:
E.g., right now you have:
class MyClass
{
public int CustomerServiceRepresentativeId { get; set; }
public string CustomerServiceRepresentativeName { get; set; }
}
Put those in a separate class, and add a property of that type to your class. E.g.:
class IdNameCombo
{
public int CustomerServiceRepresentativeId { get; set; }
public string CustomerServiceRepresentativeName { get; set; }
}
class MyClass
{
public IdNameCombo IdName { get; set; }
}
Then, you bind to the new property:
CommandParameter="{Binding IdName}"
To set or get the id or the name, you will need to type a little bit more:
MyClass myClass;
myClass.IdName.CustomerServiceRepresentativeId = 1;
myClass.IdName.CustomerServiceRepresentativeName = "Bob";

DataTrigger type to textbox/checkbox/

I have an ItemsControl in which I display different properties and values, with the name on one side and a TextBox on the other side. The ItemsSource is a collection of objects of a custom class, that has Name, Value and PropertyType properties (using reflections propertyinfo)
Now I would like to improve this by being able to detect whether the property is of type bool for example, which would display a checkbox instead of a textbox. Is this possible using a DataTrigger?
I got it semi-working using a Control of which I set the template to a textbox or checkbox according to the type, but when I try to "tab" to the next textbox or checkbox, it focuses the control that has the textbox/checkbox first, and only after another "tab" it focuses the containing textbox/checkbox/..
So if anybody know a solution for this, that would be greatly appreciated!
Use the solution you already have and set the Focusable property to false on the control that wrongly gets tab focus.
You can use DataTemplate to select different View based on Value property type.
View:
<ItemsControl ItemsSource="{Binding Path=Options}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<DataTemplate DataType="{x:Type System:Boolean}">
<CheckBox IsChecked="{Binding Path=.}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type System:String}">
<TextBox Text="{Binding Path=.}"/>
</DataTemplate>
</DataTemplate.Resources>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name, Mode=OneWay}"/>
<ContentControl Content="{Binding Path=Value}"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
ViewModel:
public class MainViewModel
{
public ArrayList Options { get; set; }
public MainViewModel()
{
Options = new ArrayList();
Options.Add(new TextProperty());
Options.Add(new BoolProperty());
}
}
public class TextProperty
{
public string Name { get; set; }
public string Value { get; set; }
public TextProperty()
{
Name = "Name";
Value = "Default";
}
}
public class BoolProperty
{
public string Name { get; set; }
public bool Value { get; set; }
public BoolProperty()
{
Name = "IsEnabled";
Value = true;
}
}

Selected RadioButton from ListBox Contents WindowsPhone8

I have placed a Radio button in a listbox content and binded it with list of QuizOption1
binding is working fine and showing the radio button checked if the property IsSelected is passed as true. the class definition is given below.
class QuizOption1
{
public int QuizID { get; set; }
public int QuizOptionID { get; set; }
public string Description { get; set; }
public bool IsSelected { get; set; }
}
While checking for the checked items, i am using following code
var lstItems = (List<QuizOption1>)lst.ItemsSource;
var selItems = lstItems.Where(op => op.IsSelected == true).FirstOrDefault();
The binding is as follows.
<ListBox Name="lst1" Grid.Row="1" >
<ListBox.ItemTemplate >
<DataTemplate >
<RadioButton
Foreground="#333333"
Background="#ffededed"
Tag="{Binding QuizOptionID}"
Content="{Binding Description}"
IsEnabled="True"
GroupName="{Binding QuizID}"
IsChecked="{Binding Path=IsSelected}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
but selItems is always null. Can anyone tell me why? Thanks in advance.
The answer is very simple, i need to add the Mode=TwoWay attribute in binding and binding looks like following.
Thanks anyways.
IsChecked="{Binding IsSelected, Mode=TwoWay}"/>

Categories

Resources