Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
This is a follow-up to my question, How does WPF handle CollectionChanged events for custom collections?.
According to Alex.Wei's answer (and the source code of IndexedEnumerable) WPF ignores the specifics of the NotifyCollectionChangedEventArgs (e.g. Action) and always reacts the same, ultimately as if Action == Reset.
So my questions: Who uses NotifyCollectionChangedEventArgs' features and, if I raise the event manually (for a custom class) does it make sense to specifiy the details (if they are never evaluated)? Also, why does WPF behave like this - isn't this a potential performance killer?
I am sorry if I didn't make things clear in last anwser. Actually, WPF behaves according to specifics of the NotifyCollectionChangedEventArgs like it means to be, and IndexedEnumerable just a tool that let CollectionView or other componets of WPF access to the source collections that didn't implement IList throngh an index easily. For example, after you bind a collection to ItemsControl.ItemsSource, the things in below will happen.
ItemsControl will specify the collection as the source of its Items property.
Items property which is an ItemCollection will obtain a CollectionView by calling CollectionViewSource.GetDefaultCollectionView method.
The view will try to subscribe CollectionChanged event of the source collection and act accordingly.
ItemCollection will also subscribe CollectionChanged event of the view and act accordingly.
And also, ItemsControl subscribe CollectionChanged event of the Items and act accordingly form the beginning.
So, the answer to you questions is that a lot of WPF classes are using NotifyCollectionChangedEventArgs' features and you definitely need to riase CollectionChanged event correctly by providing all the details whatever you collection was implemented IList or not.
My experience is that WPF is going to raise an exception if you provide wrong indices or multiple elements in an Add or Remove action.
Apart from that, there is a range of frameworks (NMF Expressions, BindableLINQ, ContinuousLinq, Obtics) that make use of these CollectionChanged events in order to implement INotifyCollectionChanged on queries. These frameworks will heavily rely on the details that you put in the event, despite you can of course always resort to a reset event.
Take a look on my ObservableComputations library. That library uses NotifyCollectionChangedEventArgs very widely.
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I need to bind a list an observablecollection to the listview. This listview must be updated each time when data changes in the observablecollection.
For now I can only bind one element of the observablecollection to the listview at the same time, whenever the second one is bound, it will cover the last one.
My purpose is to bind all the data which are created by calling LoadAlarms() in to the listview .
These are my XAML codes:
my Alarms class
My codes in viewmodel
the fist time LoadAlarms are called, I have the result
The second time LoadAlarms are called,I have the result
I would like to display these both results to the listview but I can only see the last update.
Your class Alarms must be inherited from NotificationObject and its properties must do RaisePropertyChanged whenever they change.
ObservableCollection should be allocated once and then only use add, remove etc.
Why do you have a ListView that contains a grid that contains a grid that contains another ListView? What are you trying to do if I may ask.
Hope this helps..
Each time you call LoadAlarm() you overwrite your observable collection with a new one.
Call AlarmList = new ObservableCollection<Alarms>() only once for example in a constructor.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 4 years ago.
Improve this question
I am creating a custom button control for a WPF application. The Button contains a ViewBox which in turn contains a TextBlock like this;
<Button>
<Viewbox>
<TextBlock Name="TextHolder"/>
</Viewbox>
</Button>
I want outside classes in C# to be able to access and change the text directly via a Property, like so;
public string Text
{
get { return TextHolder.Text; }
set
{
TextHolder.Text = value;
}
}
I am wondering if this is consider bad practice or not?
Thanks.
This piece of code of yours allows the part of the code that is responsible for "business logic" to look like:
this.Text = "mom";
instead of for example:
this.TextHolder.Text = "mom";
Difference is in accessing/exposing the TextHolder UI component. You don't want to expose them. That should be just a details of the 'presentation style'. Ideally the code should not care how the visuals look like (well, unless you are actually writing the code for the visual component like 'TextBlock'). What if you change your UI and TextHolder is no longer there and now you have a different presentation of the text, and it for example doesn't have control.Text but rather control.Data or control.Content? If TextHolder were exposed, you'd have to correct the code everywhere. With your piece of code, that "everywhere" uses your property this.Text, and TextHolder is hidden, so when it's gone, you just change the Text property getter/setter. This is a great thing.
And that's why, if anyone told you anything negative about this, would be wrong. Everything is better than scatterring accesses to UI component all over your business logic code. If you wanted to address that problem and came up with such a solution - great!
That being said, it's not the best you could have, and this is where the praise ends.
First of all you said you are using WPF. In WPF you there's a mechanism called data bindings. If you never used it, let me just say it's .. powerful. Unwieldy at times, but powerful. If you learned to and used data bindings, you would still have the Text property, but your code would not have TextHolder at all, not even in the getter/setter of .Text
Going further, once you learn at least the basics of data bindings, you can take it further and look at MVVM pattern. This one has the power of annihilating .xaml.cs and moving everything to view-agnostic "view models" - plain C# classes that have Properties and that never touch UI directly. WPF has mechanisms to observe them for any changes in their properties and then automatically refreshing the UI. It works two way - clicking/writing to a control may refresh properties in the "view model".
But there's a cost. It's all fine and dandy, but requires you to write some a bit repetitive boilerplace code and keep some defined patterns (though tools like i.e. PostSharp can do it for you, or frameworks like Caliburn.Micro can greatly simplify data binding expressions in XAML..).
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I am making an application where the user has to choose a value from a combobox. Based on the users choice the form should be filled with relevant labels and textboxes. How do I achieve this?
One way I think this could be achieved is by creating all labels and textboxes, and based on the users choice hide the irrelevant ones. But this seems to be very cumbersome. Is there any neat way to do it?
Could you just give me leads from where I could pick up the many
ways? #Jumpei – user2276910 8 mins ago
Just you know, everything in the comments was a lead of some kind. Whichever approach you chose, showing/hiding data is essential. Your combobox selection is a private case. Much more frequently, you gonna need/use this to handle user access so there is no way you gonna start building your application and at some point discover that you can't show/hide data or controls. That's just not the case. In fact since each approach will give you that option, to get a concrete answer will require a lot more information about the project itself and the overall architecture than just this one particular form.
Having said that I will suggest you approach which I think is not the best one, but very intuitive and at some point when you feel more confident you change this.
So in order to achieve this create the form setting the default visibility to all elements. Adding/removing controls dynamically is not that trivial but setting the visibility option is pretty straight forward so I think it's better to start by using the visibility option.
When you are ready with the default state of the form you gonna need few methods. First, an event handler for the combobox select which should be something like this:
private void ComboBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
ComboBox comboBox = (ComboBox) sender;
string userSelection = (string)ComboBox1.SelectedItem;
From now on you should make a few things. First check if the userSelection is something valid. This check is essential, after you are sure that this is valid selection you gonna proceed (and we are still in the SelectedIndexChanged event) by calling a a method :
private void SetControlsToDefault()
{
}
This method will contains all your controls with their default visibility status. That's required because when the user make more than one selection with the combobox if we don't hide the once that were shown on the previous selection you will end up with visible controls when they should be hidden for the certain selection.
So once we are sure that the form is returned to it's initial state we need to check what exactly has the user selected and show the relevant controls.
Here some would suggest to use switch I'll suggest if-else if statements since I think this will make it more understandable but you can change it if you like so again in the event handler after calling SetControlsToDefault(); we have this:
if (userSelection.Equals("selection1"))
{
ShowControlsForSelectionOne();
}
else if (userSelection.Equals("selection2"))
{
ShowControlsForSelectionTwo();
}
else if (userSelection.Equals("selection3"))
{
ShowControlsForSelectionThree();
}
where ShowControlsForSelectionOne(), ShowControlsForSelectionTwo(), ShowControlsForSelectionThree() are all private methods where you gonna set the visibility only to those elements relevant to the selection. And that should be all. This is one of the many ways to complete this task.
It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I'd like to create a WPF application and would like some advice on the most appropriate approach.
I want to create an RSS reader that automatically refreshes when a new RSS entry is added. The problem is that I don't want to use traditional controls (listbox/listview) to display the data. I'd like the feed items to appear in panels randomly on the screen. These panels consist of several textblocks. Each panel displays one feed item.
It would look something like this:
Concept
This raises several questions:
1: Generate panels completely from code, or use a Custom Control?
I would model a class like a panel as described above. This class manually adds all controls to the form and drops the panel at a random location on the form. When a new RSS entry is added, an instance of this class gets instantiated and passes the rss information as parameters.
On the other hand, it might be better to create an UserControl for this. Is it easy to create this UserControl by code and pass it the parameters in the constructor?
2: Can my data/panel automatically update when a new RSS entry has been added online?
Right now I would refresh everything each (x) seconds and check against a collection of panels if there has to be created a new one. If so, create a new panel and drop it randomly on the form.
Is there a better way of doing this? I can use a local ObservableCollection with databinding that automatically updates a control (listbox, etc) when the collection changes, can this also be done with an online source like an RSS feed?
The most ideal way would be that my application gets notified when a new RSS entry has been added, downloads the last entry and creates a new Panel (trough code or trough a UserControl)
If this is hard thing to accomplish, I'll use the traditional refresh method.
3: Do I have to use DependencyObject/DependencyProperty?
I know DependencyObject & DependencyProperty expose some powerful functionality for UserControls, but I don't really know how to use them. Are they necessary for this kind of application?
4: Do I have to use WCF (Windows Communication Foundation)?
I'm not really experienced with "advanced" WPF stuff like advanced databindings, DependencyObjects and UserControls, but I love to learn!
I would recommend firstly looking into using the MVVM design pattern, and using an MVVM framework. Secondly, you could achieve this effect using an ItemsControl and use a Canvas as it's ItemsPanel type, then you could use a custom ItemTemplate which renders each data object using a UserControl.
The user control would have a dependency property which is the data item, and you would bind this in the item template declaration.
You could have a model which models each RSS entry (RSSEntry) and perhaps an RSSEntryViewModel which adds the x and y coordinates on the canvas.
Your screen view model would then have an ObservableCollection of RSSViewModel which you would add/delete etc to and the UI would automatically update.
You wouldn't need a service layer if you didnt want to, but as long as your view model retrieves the entries via an abstraction, it should be easy to refactor in the future.
Generate panels completely from code, or use a Custom Control? I usually try to do as much as I can in XAML declaratively, separating logic and presentation usually helps scalability of the application and code quality - but of course there are limits. UserControls generally are not supposed to have parameters in their constructors (not that they can't have them, but you have to have a parameterless constructor so the class can be instantiated from XAML).
Can my data/panel automatically update when a new RSS entry has been added online? There has to be something to send update notifications to the WPF layer, so it can update the display. In case of a RSS application, I guess you will have to manually periodically scan the RSS channels for updates (RSS is a pull technology) and in case of update add the item into the ObservableCollection which will send the appropriate update notification for you.
Do I have to use DependencyObject/DependencyProperty? No, you can use INotifyPropertyChanged. DependencyProperties are generally used in properties which will serve as binding target (the property that is declaring the binding) or in properties that will take advantage of any other DP feature - value inheritance or animation. INotifyPropertyChanged is enough for the properties that are bound to (that are named in the binding expression). Note that you can use NotifyPropertyWeaver to generate the notifications for INotifyPropertyChanged automatically - you just create the OnPropetyChanged method and the weaver will then call it whenever any property of the object is changed! And it even integrates beautifully with Visual Studio.
Do I have to use WCF (Windows Communication Foundation)? For WCF you have to have something to communicate with - it is a communication framework after all. Do you?
You should use a WPF listview (or similar; not sure which control exactly), and theme it to match your desired "panel" idea. That is one of the great strengths of WPF. Then you get all the benefits of the built-in control, with any look you want.
Bind to the ObservableCollection; how you update that observable collection is your business. I don't think RSS has a "push notifications" part of its spec, so polling is how these things are usually done. But in the end it doesn't really matter; that part of your code is completely separate from WPF, so as long as it updates the ObservableCollection, you're good.
Either DependencyObject/DependencyProperty or INotifyPropertyChanged are generally necessary for any kind of WPF application with databinding. It's worth learning them, and then maybe learning a framework that abstracts them away for you.
No; WCF has nothing to do with WPF. You can use any technology to talk to the server that you like.
1: Generate panels completely from code, or use a Custom Control?
Create two view model classes. One class will model the view of all your items, and one representing the content of a single item. The former will contain an observable collection of the latter.
Build a user control to display each.
The container view will be an ItemsControl whose ItemsSource is bound to its collection of item view models, whose ItemsPanel is a Canvas, and whose ItemContainerStyle binds Canvas.Top and Canvas.Left properties to Top and Left properties in the item view models. When a new item is added to the view model's collection, binding will automatically create a new panel for it.
The item view models will generate the random values of Top and Left themselves. (You could also have them request the values from the container when they're constructed.)
(If the term "view model" doesn't mean anything to you, you need to research the model/view/view model pattern, aka MVVM.)
2: Can my data/panel automatically update when a new RSS entry has been added online?
First off, you need to research how RSS aggregators work, since you're writing one. That will explain to you the mechanics of getting updates from RSS feeds. That problem is completely distinct from the problem of presenting the updates once you get them.
Your RSS aggregation layer will check feeds, look for new items, and when it finds new items, raise an event. Your UI layer will handle events raised by the aggregation layer and create new view model objects for every new item received.
This use of events completely decouples the two components from each other. For instance, you can test your UI by building a mock aggregator that generates test messages and having your UI listen to it instead of your real aggregator. Similarly, you can test your aggregator without building the - you can just build a listener that registers for its events and dumps items to the console.
3: Do I have to use DependencyObject/DependencyProperty?
You probably won't don't have to implement your own, no.
4: Do I have to use WCF (Windows Communication Foundation)?
Why wouldn't you?
I have a situation where I need to know when an item is going to be added/removed/modified in the collection.
I tried by inheriting BindingList in a class that will trigger these events, however the "adding" event doesn't work. The only way I found it working is by overriding EndNew() method, however I don't find a way to get which object is going to be added in this method (if someone has a solution for this, it's ok too!).
So built a totally new class which inherits from same interfaces/class of BindingList and implemented everything (I didn't inherit, however, ICancelAddNew).
I bound it through databindings to my listbox and I find out that nothing works (listchanged events neither listchanging events). How can I simulate BindingList behavior on a listbox?
Any suggestion heavily appreciated, I don't have any other ideas for a workaround
EDIT 1:
This is my collection: http://pastie.org/1978601
And this is how I bind the collection to the ListBox
SpellCasterManager.CurrentProfile.ButtonsMacro.ListChanged += new ListChangedEventHandler(ButtonsMacro_ListChanged);
SpellCasterManager.CurrentProfile.ButtonsMacro.ListChanging += new Expand.ComponentModel.ListChangingEventHandler(ButtonsMacro_ListChanging);
gumpButton.DataBindings.Add("Value", SpellCasterManager.CurrentProfile.ButtonsMacro, "GumpIndex", false, DataSourceUpdateMode.OnPropertyChanged);
Actually under subscribed events there is just a MessageBox.Show("bla");
Your collection won't detect property changes in an existing item because it doesn't hook into the item's property changed events as it is added to the collection.
BindingList<T> does listen to PropertyChanged on your item and does fire a ListChanged event when an item is added to the BindingList and it does include the index at which is is added. Try it in a test app without WinForms.
Adding an existing item is not the same as AddNew(). The AddingNew event is only called when AddNew() is called and allows you to supply the new instance.
When WinForms is involved, things get more complicated. There is the CurrencyManager to think about and also BindingSource. If no events are firing at all then check to see if you are using the CurrencyManager/BindingSource you think you are.
I don't think anything in the framework uses INotifyPropertyChanging, only the original INotifyPropertyChanged. You might want to use Reflector on BindingList to see how the hooking is done and then try to incorporate INotifyPropertyChanging if your item supports it.
Did you follow MSDN guidelines? Your collection class should extend CollectionBase and implement IBindingList - and that should be fine.
Also, you might want your collection item to implement IEditableObject in order to support *Edit operations. This however is not required - more importantly, your collection item should have a way to notify parent collection when it changes (either by following code provided on MSDN, or using for example INotifyPropertyChanged).
You can find working binding sample implementing custom CustomersList on IBindingList doc page (Customer class can be found on IEditableObject doc page).
After getting clear idea of what you are looking for i will suggest following things
Here is a great undo framework which provides lot of functionality.
http://undo.codeplex.com/
Here is sample,
http://blogs.msdn.com/b/kirillosenkov/archive/2009/07/02/samples-for-the-undo-framework.aspx
And in your case, instead of trying to hook on adding/editing events, it's better to track after added/modified/deleted event if you store their initial state. So if the item was removed, in your previous state you will have the item already if you started tracking from the start state of your program.