I have a WPF application with an XAML Window containing a few Buttons and a DataGrid. When buttons are pressed, some logic is performed in the background which builds a list of some type and finally assigns the list to a (MVVM) model property "DataSource" to which an ItemsSource of the DataGrid is bound to like:
<DataGrid x:Name="DataGrid" Grid.Row ="10" ...
ItemsSource="{Binding Path=DataSource, Mode=TwoWay, NotifyOnSourceUpdated=True, NotifyOnTargetUpdated=True}">
When the content of DataSource is changed, DataGrid is aware of that and shows the new data. So far all good, application works as intended and with no problems. I can copy the bin output of build and sucessfully run it just about everywhere.
Then comes ClickOnce publish. If published so that it installs from, and is installed from an Unc network share, e.g. \SomeServer\SomePath\InstallFromDir\, everything still works fine.
But if published so that it installs from, and is installed from an online url, e.g. http://companydomain.com/InstallFromDir/, DataGrid simply does not update.
Nothing else is changed but the method of app and updates availability from unc to web.
What I gathered from debugging trace points still applies. The list in the background is built anew. It is assigned to the DataSource property (if I verify the contained data, it does contain the new data). But if I access the DataGrids ItemsSource it still contains the OLD, initial data.
I have tried re-assigning the DataSource to ItemsSource -- doesn't help. I have tried re-binding the data when it changes programatically, as in:
var sourceBinding = new System.Windows.Data.Binding
{
Path = new PropertyPath("DataSource"),
Mode = BindingMode.TwoWay,
NotifyOnSourceUpdated = true,
NotifyOnTargetUpdated = true
};
BindingOperations.SetBinding(((MainWindow)_window).DataGrid,
System.Windows.Controls.DataGrid.ItemsSourceProperty, sourceBinding);
and even changing the xaml so that it is ONLY bound in code:
<DataGrid x:Name="DataGrid" Grid.Row ="10" ... >
and it still works the same as described above: works as direct copy or unc install, but doesn't work as web install.
I am totally lost as to either finding the cause or finding the workarounds. Anyone encountered this before? Any ideas? Many thanks!
Update: I have initially thought this was a DataGrid issue, but I have since also tried replacing DataGrid with ListView, and it doesn't work either.
Related
In my WPF project, I have the Visibility of a Grid bound to a bool with a BooleanToVisibilityConverter:
<Grid ... Visibility="{Binding SelectedElement.HasError, Converter={StaticResource ResourceKey=BoolToVis}}">
However on startup the grid is always shown for a few milliseconds, even though the element/class holding the bool field is not even created, and after creation is defaulted to false.
How can I prevent the grid from showing up on startup? I tried to implement a FallbackValue for the binding, because the object in the path is not yet available, but setting "Visible" or "Hidden" here doesn't change anything.
(Posted on behalf of the OP).
Works fine with FallbackValue=Collapsed.
I am having a furious struggle with the WPF Combobox in our bi-languge application.
I have the combobox binded to a collection. I have a button that replaces the values of the collection with their corresponding string values in another language.
What is the problem: I select a value from the drop down list. I change the language, by pressing a button, then the displayed value remains on the old language, but when the drop down is dropped the values in in are replaced with the right ones.
Here is my XAML:
<ComboBox x:Name="ProjectClassComboBox"
Width="150"
ItemsSource="{Binding Path=ProjectClassCollection}"
DisplayMemberPath="Name"
SelectedValuePath="Id"
SelectedValue="{Binding Path=RegionContext.CurrentItem.ClassNomenclatureId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Update: Because it is asked in the comments I must add that
the collectionis a custom class of ours, DERIVED from ObservableCollection, that is fairly complex. The collection items must be implementing INotifyPropertyChanged, and the collection has a listener to the PropertyChanged event of each item.
It just looks like the displayed text of the combo is not updated, when the drop down list and the selected item value is updated.
Binding ObservableCollection (and derrived class too) works only in case where you add or delete items, cause that's the action that invokes change event. If you need to manipulate data inside collection I suggest using BindingList. Maybe some kind of wrapper would be solution for you.
Do one thing. In the button click,
1. get the selected index in the combo box
2. Replace all the strings in the collection
3. set the selecteditem property of the combobox using the selected index that we have stored earlier in the step 1.
So, it's a bit late but we just encountered the same problem on a project that needs to support multiple languages.
Our solution was to return a new instance of ObservableCollection on the property getter.
So, your code should look like this:
<ComboBox x:Name="ProjectClassComboBox"
ItemsSource="{Binding Path=ProjectClassCollection}"/>
And in your ViewModel:
public ObservableCollection<Project> ProjectClassCollection
{
get {return new ObservableCollection<Project>(){_projectClassCollection};}
set {...}
}
This code is a quick snippet from my memory. It will not work if you just copy-pasta, but the idea is that another collection instance worked for us.
We tried to call OnPropertyChanged(nameof(ProjectClassCollection)) but that didn't work. We tried to set UpdateSourceTrigger=PropertyChanged in XAML but that didn't work either. Having a new instance worked.
Hope this helps and saves you time, cheers!
I have Listview with templated items (which looked just like Windows Explorer). My problem is when I openning folder which contains a whole lot of files that ListView loads those files not smoothly.(see video: http://screencast.com/t/bY7ucELj9I).
Does someone has any idea how to solve it?
You may need to virtualize your ListView's Items. Example
<ListView Name="ListViewWithVirtualization" Height="100" Margin="5"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling" />
If you set VirtualizingStackPanel.VirtualizationMode = “Recycling” then each container will get reuse instead of destroy. You will get better performance by specifying VirtualizationMode to Recycling than basic default virtualization. See http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel.aspx
I have a WinRT C# app with two ListViews. A simple way to represent it is that one ListView is a list of folder locations, and the second ListView details the directory structure inside that folder:
ListView1 ListView2 (Contents of Folder 2)
Folder 1 Folder a
|Folder 2| File a
Folder 3 File b
Folder 4 Folder b
Folder c
File c
File d
Something like that.
I have a main ObservableCollection, which is a collection of folders. Each folder contains its own ObservableCollection, which is the data used in the second ListView.
ListView1 and 2 are bound the same, essentially:
ItemsSource="{Binding Source={StaticResource folderViewSource}}"
ItemsSource="{Binding Source={StaticResource fileViewSource}}"
With the CollectionViewSources being defined so:
<!-- The list of folders, used by the main ListView -->
<CollectionViewSource
x:Name="folderViewSource"
Source="{Binding FolderBinding}" />
<!-- The files and folders for a specific folder, used by the Files ListView -->
<CollectionViewSource
x:Name="fileViewSource"
Source="{Binding ElementName=folderListView, Path=SelectedItem.Files}" />
ListView1 populates fine, no problems.
ListView2 does bind correctly (it shows the files for the selected folder in the first ListView), but the binding is done on the UI thread. On my PC, it's tolerable if unpleasant. On my Surface RT, it can take a good 2 seconds.
The template used in the second ListView is quite fiddly, but I filtered it down to just a string and it was still a bit jerky on the Surface - obviously I need to move it off of the UI thread.
My first thoughts were to move the binding away from the XAML and do it in code, but I couldn't see any way to improve it - Windows is still creating the UI elements on the UI thread regardless of what I do.
I also looked at ISupportIncrementalLoading but that seems to be for dynamically loading new items as you scroll, etc.
I've been stuck for a while now, I've had things keeping me busy but I want to get back to this, but I can't figure this out. Hopefully I'm missing something obvious.
I am trying to understand Binding so I have come up with a very simple program to try and test it.
I have the following element in my MainWindow:
<ComboBox Name="comboBox1" ItemsSource="{Binding ComboItems}" />
In my Code I have the following observable collections:
private readonly ObservableCollection<string> comboItems =
new ObservableCollection<string>();
public ObservableCollection<string> ComboItems
{
get {return comboItems; }
}
I can successfully add items this way at any point during runtime as long as the combobox was in the MainWindow XAML from the very beginning:
ComboItems.Clear();
ComboItems.Add("Item");
My question is, how can I get this ComboBox to update if I load it from a file? I have the following code to save and load the file:
File.WriteAllText("ComboBox.xaml", saveComboBox)
This is just the last line in my save I have other items that don't seem to matter for this discussion.
ComboBox comboBox = System.Windows.Markup.Xamlreader.Load(stream) as ComboBox;
This saves and loads my combobox successfully.
The problem I am encountering now is that the code:
ComboItems.Clear();
ComboItems.Add("Item");
No longer works. I am in the process of trying to learn Data Binding for a new project that I will be doing. This project will require the loading of xaml files for the user interface and I need to fill the ComboBox after it has been loaded.
What is the simplest and most efficient solution to this problem?
I don't know if the XamlReader will even preserve the bindings, read the documentation, it has limitations. I would not recommend doing this anyway. If the binding is gone you could create a new one in code, partially defeats the purpose of saving it of course.