I have list of employers that binding to data and fill from special form. When I go to form I have every text boxes clear. I fill all of them and save new employer to list. But if I try to add new employer I have textboxes with previous text in form. And variables that bind to text boxes in form are all null.
Is there way to solve problem without using solution like that: Textbox.text=null;?
I'm using MVVM pattern in my app. I'm also using catel snippets to define viewmodel and properties. There is code of ViewModel of page with employer properties:
public EmployerModifyViewModel(TransferParameter parameter, IEmployersListManage employersListManager)
{
//in "parameter" I pass values fo Current employer (it can be empty
//if we need to add new object to list or it can be some employer from list)
_employersListManager = employersListManager;
SaveEmployerCommand = new Command(OnSaveEmployerCommandExecute);
CanselSavingCommand = new Command(OnCanselSavingCommandExecute);
if (parameter.Value is EmployerClass)
{
CurrentEmployer = parameter.Value as EmployerClass;
}
}
public EmployerClass CurrentEmployer
{
get { return GetValue<EmployerClass>(CurrentEmployerProperty); }
private set { SetValue(CurrentEmployerProperty, value); }
}
/// <summary>
/// Register the CurrentEmployerBase property so it is known in the class.
/// </summary>
public static readonly PropertyData CurrentEmployerProperty = RegisterProperty("CurrentEmployer", typeof(EmployerClass), new EmployerClass());
There is example of binding to properties in xaml:
<ContentControl Content="{Binding CurrentEmployer, Mode=TwoWay}">
<ContentCntrol.Recources>
<DataTemplate DataType="{x:Type employer:EmployerClass}">
...
<TextBox Grid.Column="1"
x:Name="EmpName"
Width="300"
Height="30"
FontSize="14"
Text="{Binding Name, Mode=TwoWay}" //Property "Name" of CurrentEmployer
HorizontalAlignment="Left"
Margin="20,20,0,0"/>
I think u should use the below code where u add the new employee. Everytime the button is clicked the textboxes go empty.
txtbox_1.Text = String.Empty;
txtbox_2.Text = String.Empty;
.............
Thank you for all, problem solved. I removed ContentControl and DataTemplate from xaml and I made bindings like this "{Binding CurrentEmployer.Name, Mode=TwoWay}".
Related
I am trying to modify a existing WPF application in a way so that a newer version of some data object can be used alongside the old one. And so i avoid redundant code by extending the existing ViewModel with new fields where the old ones cannot be reused.
public IList<G1VU.PDR> VuG1 { get; set; }
public IList<G2VU.PDR> VuG2 { get; set; }
public PlacesCompound VuP
{
get
{
if (VuG1 != null && VuG2 == null)
{
return new PlacesCompound {
G1 = VuG1,
G2 = null
};
}
if (VuG2 != null && VuG1 == null)
{
return new PlacesCompound {
G1 = null,
G2 = VuG2
};
}
throw new Exception("G1 and G2 data present or no data present");
}
}
VuG1 has existed before and i have added a new property VuG2 for the new data. As you can see these are not the same class so i cannot interchange them. For that reason i've added a property that will return either of the two in a PlacesCompound class, which is just a class with two properties and nothing else.
In the corresponding usercontrol (lets call it ActivitiesView) we have a DataGrid which binds to the ViewModel and somewhere a TabItem that will display a custom UserControl places which binds to VuG1 on the ViewModel. I have copied it and changed it so it will work with VuG2 Data.
And i created a custom DataTemplateSelector which will decide what Template to use based on which variable of PlacesCompound isnt null.
In VUActivitiesResources.xaml i have then declared 2 DataTemplates one for each places UserControl and the DataTemplateSelector.
<activities:VUActivitiesViewDataTemplateSelector x:Key="PlacesTemplateSelector"/>
<DataTemplate x:Key="VuG2Template">
<places:VUPViewG2 DataContext="{Binding VuG2}" HorizontalAlignment="Left"/>
</DataTemplate>
<DataTemplate x:Key="VuG1Template">
<places:VUPViewG1 DataContext="{Binding VuG1}" HorizontalAlignment="Left"/>
</DataTemplate>
VUActivitiesResources.xaml is being referenced in ActivitiesView as UserControl.Resources.
In the ActivitiesView i placed a ItemsControl into the TabItem replacing the custom places UserControl (ive also tried a ListBox instead of a ItemsControl, but neither works)
<TabItem IsEnabled="{Binding PlacesIsVisible}">
...
<ItemsControl
ItemsSource="{Binding VuP}"
ItemTemplateSelector="{StaticResource PlacesTemplateSelector}"></ItemsControl>
</TabItem>
My question: why PlacesTemplateSelector is never used and how do i make it being used? Because right now while debugging i can see that in ViewModel VuP returns a PlacesCompound object correctly but the Selector is never entered. I want one of the two DataTemplates to show up in the TabItem and right now none is showing.
ItemsSource must be a collection (which your PlacesCompound is not), in your case this would be either VuG1 or VuG2. If the two item classes have no common base class, you can still use IEnumerable:
public IEnumerable VuP => (IEnumerable)VuG1 ?? VuG2;
Then, instead of writing a TemplateSelector, just let the WPF DataTemplating mechanism do its work:
<DataTemplate DataType="{x:Type namespace1:PDR}">
<places:VUPViewG2 HorizontalAlignment="Left"/>
</DataTemplate>
<DataTemplate DataType="{x:Type namespace2:PDR}">
<places:VUPViewG1 HorizontalAlignment="Left"/>
</DataTemplate>
<ItemsControl ItemsSource="{Binding VuP}" />
Starting with the MahApps-Material mashup demo, I'm trying to use a button click event to create a new TabItem from my Views. For now, the CustomTabItem will show text bound to some property from a FancyObject (being served to the View from my FancyTabViewModel). But I've got the DataContext, dependency property or the Binding done wrong.
public void NewTabOnClick(object sender, RoutedEventArgs e)
{
// create my new object from Models
FancyObject fo = new FancyObject();
// create the INofify VM and pass it my object
// the VM has a public VMFancyObject property to serve the fo
FancyTabViewModel fvm = new FancyTabViewModel(fo);
// create the new UserControl and set its context to the VM
CustomTabItem newTab = new CustomTabItem() {
Header = "New tab"
};
newTab.DataContext = fvm;
MainWindowTabs.Items.Add(newTab);
}
And in my <TabItem x:Class="MyProject.Views.CustomTabItem" there is a label so bound: <Label Content="{Binding VMFancyObject.SomeList.Count}"/>
I expect to see the default count of the List created in the FancyObject's constructor. However, after the new tab is created and added to the dragablz:TabablzControl, I just see a blank label.
I also tried <Label DataContext="{Binding Path=DataContext.FancyTabViewModel,RelativeSource={RelativeSource AncestorType={x:Type TabItem}}}" Content="{Binding VMFancyObject.SomeList.Count}" HorizontalAlignment="Left" Margin="341,196,0,0" Foreground="Black" Background="#FF97FF02"/>
I'd like to have a list of TextBlocks with ComboBoxes next to each of them.
The data source of ComboBoxes should be the same for every ComboBox. Each TextBlock however should contain sequent element of List
Both data source for ComboBoxs and TextBlocks are in my "settings" object. So I set DataContext of the whole window to this settings object.
Here's my problem:
Data source of TextBlock is: List called Fields, which is inside of an object called "Header" of type "Line" (which is of course inside settings object, which is my datacontext).
So, graphically:
settings(type: Settings) - Header(type: CsvLine) - Fields(type: List of string)
Now ComboBox. Data source of every ComboBox should be a List called Tags
Graphically:
settings(type: Settings) - Tags(type: List of string)
I don't know how I should point to these locations, I tried a lot of options, but none of them work. I see just a blank window.
Here's my code:
<Grid>
<StackPanel Orientation="Horizontal">
<ItemsControl ItemsSource="{Binding Headers}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Fields}"/>
<ComboBox ItemsSource="{Binding DataContext.Tags,
RelativeSource={RelativeSource AncestorType=ItemsControl}}">
</ComboBox>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
I have no idea what I should actually pass as ItemsSource to ItemsControl, because I think it should be common source for both TextBoxes and ComboBoxes, but their only common source is settings object - but i already set it as my DataContext.
I have used RelativeSource in ComboBox, but I'm not really sure what it's used for (although I read an article about it on MSDN). I don't know why but it's really hard for me to understand binding - I'm struggling to get anything working.
//EDIT:
Here's my Settings class - which is the type of my settings object:
public class Settings
{
public CsvLine AllHeaders1
{
get
{
return _allHeaders1;
}
}
public CsvLine _allHeaders1 = new CsvLine()
{
Fields = new List<string>()
{
"Header1" , "Header2" , "Header3"
}
};
private List<String> _tags;
public List<String> Tags
{
get
{
return new List<string>() { "Tag1", "Tag2", "Tag3", "Tag4", "Tag5" };
}
set
{
_tags = value;
}
}
}
And here's my CsvLine class:
public class CsvLine
{
public List<string> Fields = new List<string>();
public int LineNumber;
}
So, I'm not 100% sure of what it is you want, but the following should get you started.
Firstly, you need to ensure you bind to public properties - not public members - so the CsvLine.Fields member needs to be changed to public List<string> Fields { get { return _fields; } set { _fields = value; } }. Also not that, if you want changes in the settings object to be reflected in the UI, you will need to implement INotifyPropertyChanged.
Anyway, with this in place and assigned to the DataContext of the grid, the following will display a vertical list of text blocks (showing "Header 1", "Header 2", "Header 3") each with a combo box to the right containing the values "Tag1", "Tag2" ... "Tag5".
<Grid x:Name="SourceGrid">
<ItemsControl ItemsSource="{Binding Path=AllHeaders1.Fields}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding}" />
<ComboBox ItemsSource="{Binding ElementName=SourceGrid, Path=DataContext.Tags}" />
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
Hope it helps.
I have this block of code as you can see in the screen print correctly loads the data you want and store the list of objects PopularVideos:
item { Title = Hey Porsche, Url = http://www.unnu.com/wp-content/plugins/wordpress-popular-posts/timthumb.php?src=http://www.unnu.com/wp-content/uploads/2013/03/019.jpg&h=65&w=275 } <>f__AnonymousType0<string,string>
item.Title "Hey Porsche" string
item.Url "http://www.unnu.com/wp-content/plugins/wordpress-popular-posts/timthumb.php?src=http://www.unnu.com/wp-content/uploads/2013/03/019.jpg&h=65&w=275" string
Need to load these objects in my list box with binding or has otherwise also can be. But the windows phone does not work with DataSource and DisplayMember.
My XAML:
<ListBox Name="listBoxPopular">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Name="imagem" Source="{Binding Path=Url}"/>
<TextBlock Text="{Binding Titulo}" Tap="HyperlinkButton_Tap" FontSize="30" Foreground="#FF159DDE" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PanoramaItem>
My Class is:
class PopularVideos
{
public PopularVideos() { }
public PopularVideos(string titulo, string url)
{
Titulo = titulo;
BitmapImage Img = new BitmapImage(new Uri(url));
}
public string Titulo { get; set; }
public Uri Url { get; set; }
}
and my codebehind is:
_popVideos = new List<PopularVideos>();
var data = e.Document.DocumentNode.SelectSingleNode("//div[#class='content']")
.Descendants("img")
.Select(img => new
{
Title = img.Attributes["alt"].Value,
Url = img.Attributes["src"].Value,
}).ToList();
foreach (var item in data)
{
PopularVideos pop = new PopularVideos(item.Title, item.Url);
_popVideos.Add(new PopularVideos(item.Title, item.Url));
}
listBoxPopular.ItemsSource = _popVideos;
This code works because they are carrying the images and links in the objects, just can not bring up in my list box.
Have a bindable ObservableCollection<Item> (preferrably in a ViewModel).
Use the ListBox.ItemsSource property to bind to said ObservableCollection<Item>. The standard binding rules apply.
Each of the items in ListBox will be a representation of the items in the core collection that is bound to the control, so bind to its properties the same way you would to anything else.
It's reply to comment:
Ok, please read once again the article that #Den send to you. And please remove DataContext Property from ListBox, add x:Name="myList" to ListBox and in code-behind: myList.DataContext = this; This is not the best solution, but it's easy to understand and firstly you need to understand it :) Best regards.
I have a dataBinding ListBox in a Pivot section.
In another Pivot section i have a form to create new items for the ListBox.
When i add a new item to the ListBox i need to acces to the new ListBoxItem for find a TextBox control and modify the Text value, but
ListBoxItem lbItem = allItemsListBox.ItemContainerGenerator.ContainerFromIndex(itemIndex) as ListBoxItem;
Always returns null.
The problem seems to be that the ListBox is not visible, so the new ListBoxItem is virtual.
How can i resolve that?
Thanks.
Why not use data binding with DataTemplates instead of trying to modify the controls directly?
for example:
Code:
// Data binding class
public class Data
{
// Implement INofifyPropertyChanged
public string Text { get; set; }
}
// Code to bind it to Pivot
ObservableCollection<Data> list = new ObservableCollection<Data>();
// populate list
Pivot1.ItemsSource = list;
XAML:
<Pivot Name="Pivot1">
<Pivot.ItemTemplate>
<DataTemplate>
<TextBlock Text={Binding Text}" />
</DataTemplate>
</Pivot.ItemTemplate>
</Pivot>
Now, to change Text of a specific TextBlock, all you need to do is change a value of associated Data object to it from the list.