A comment list Using WPF - c#

I would like to know create this sort of comment list with WPF using using input from the user. He will input the username and a comment. Then he will press submit. There will also be a time stamp on every comment submitted. Then the system will have a limit of 5 comments once a different user inputs the 6th comment the first one will be deleted and then the 2nd comment submitted will become the first and so on until the users stop submitting.
Sadly I am completely stumped and just can not figure out how to even start it, so some help would be greatly appreciated.

I would personally go with something around this way:
ViewModel layer
You will need to create a UserComment class containing the following properies
UserName,Comment,TimeStamp
Another class which acts as the ViewModel of your UserCommentsView containing a property UserComments which returns an
ObserableCollection of UserComment type.
A ViewModel.AddUserCommentCommand property which adds a comment to
UserComments - but before it checks the count of items in
UserComments and removes the first/last (depending on your design)
before adding a new comment.
View layer
A listview with the above ViewModel as its context + items source
being ViewModel.UserComments.
A Button with its command bound to ViewModel.AddUserCommentCommand.
Have a look at Basic MVVM Listbox Binding in WPF for MVVM binding.
and if you prefer code-behind: ListView, data binding and ItemTemplate

Related

Should I create a ViewModel for each item in an ObservableCollection

Being fairly new to MVVM in WPF I am running into a dilemma of what items need their own ViewModel. I am writting a plugin for Autodesk's Revit program. Using the provided API I am drilling into the parameters of elements and performing engineering calculations in a way that is easier for the end user to understand. I have outlined my approach in the image below.
The element is a model element in the program that is selected manually. An instance of the FPB class is then created by pulling parameters from the element and assigning them to the FPB's properties. The ViewModel contains an ObservableCollection that contains a list of FPB objects the user has selected. Using a combobox the user can select which FPB they want to edit. The WPF page then shows the respective values for the properties that the user needs to interact with to perform their engineering calculations.
Using WPF's databinding the values can be changed in the View and the value is subsequently changed in the ViewModel's FPB in the ObservableCollection. In order to write these values back to the Element in Revit the change needs to be raised in the API's ExternalCommand and ensured in a transaction. It then executes a method that writes the values back to Revit.
My issue is for each value changed in the view the data needs to update the element. This element is performing its own calculations that are changing the data values. These updated value then need to return all the way back to the view. The round trip is shown below.
View -> ViewModel -> FPB in ObservableCollection -> Update Element -> FPB in ObservableCollection -> ViewModel -> View
To adhere to MVVM principles do I need to create a FPBViewModel for each FPB instance? Will this allow for an easier flow of data? Or is this just unnecessarily complicating the data flow. I can add code snippets if need be, but this appears to be more of a theory question than code specifics question. Thanks in advance.

Mvvm - How to capture in the ViewModel, the UI's data-bound Control's Name/Id, using a Parameter Command? Is there a clear cut way I'm missing?

Mvvm, Wpf, VS2015
Hi All! I have googled this till my fingers bleed! But just hacks and work-arounds, or partial use of code behind.
My Wpf-Mvvm app uses Speech Synthesis.
Each button, (and in the next iteration, buttons using the selectedItem Index of Lists or ComboBoxes, to select the content(text)to be synthesized) specifies different content to be synthesized.
Sticking with Mvvm principles, in my viewModel, I need to capture which button, based on the List or ComboBoxes' SelectedItem/Value that is bound to the Parameter Command.
Why? So I can have the app synthesize the content(text/words)the user selects to hear. If not, I have to make separate commands and speech synthesizer methods for each.
There must be a simple clear-cut way. What am I missing here?
I thought of updating the Model's properties to reflect user's selection and use User Settings to persist,but have not tried yet.
Otherwise the Model's properties are accessible so far as encapsulation-wise to the ViewModel, but the property values from the Model still are not visible in viewModel.
I need the command bound control's ID/Name to route the content to be synthesized based on the model's class properties. But when I instantiate the model from the viewModel,
the model's properties are not there. I presume instantiating the Model class object from the viewModel, is in a different memory location, than the Model.
So I will try using User Setting's persistence for these properties, if no one else has a better way.
There has to be a clear solution to this, I hope :)
I know the View and ViewModel are supposed to not need to know what the other is doing. In this case though, I clearly need the List or ComboBoxes' Id or Name and their SelectedItem index.
I also need the button's Id or Name, because I have several groupings of content to choose from, and several buttons starting the synthesizing method.
Example: If the text content of an announcement to be synthesized, held in separate XML(SSML) files with identifier key values of 941, 23, 508, etc.,
I need to know which the User Selected to hear.
I imagine simply capturing in the viewModel, the Data-bound List/ComboBoxes' Selected ID index would suffice.
Thank you so very much for your help.
-Flazz

Multiple custom controls affects control visibility

Ok, this is going to be a 1000ft long question, but there's a lot to cover so here goes:
I am creating a paged items control, the purpose of which is to display very large collections in a paged format. I've created a repository on GitHub which can be found here. I have removed any styling for simplicity.
Upon starting the application, it looks like this:
This is pretty straightforward really, there's navigation buttons, an items per page selector but that isn't really important. The problem here is when you click the button "Open New Window".
This will open a new MainWindow, but on the first window, the collection disappears, as shown below:
The image above shows the old window in front, as you can see, there is no list of content as there is on the new window.
So, after smashing my head against a wall for a couple of hours, I am in need of assistance. I'll provide an overview of how the project is structured.
AnagramPagedItemsControl
The control being used for displaying the content is a custom control called AnagramPagedItemsControl, it is responsible for handling navigation between pages. I think the key property here is the PagedCollection.
The PagedCollection dependency property holds the collection which is bound to the Models property in the TestItemsViewModel.
TestItemsViewModel
This is the DataContext of the MainWindow, each window instance should create it's own view model. The CreateTestItems() method is responsible for creating the list of test items.
LazyPagedCollection
The purpose of this collection is to encapsulate the logic of a paged observable collection, it only loads pages when they are needed, hence the laziness.
It exposes methods like NextPage which are called in the AnagramPagedItemsControl when the user clicks on the various navigation buttons. The view model can also call navigation on the LazyPagedCollection, this allows the view model to call navigation without having to go through the view to do it.
TL;DR
When I create a new Window, the content of the previous window disappears. The problem is almost certainly with the control however I am stuck as to how to fix the problem.
This is quite a large problem to look at so I'd be very grateful for anyone who can look into it. Again, the source code is here, please feel free to suggest alternatives or pick out anything that I may have overlooked.
Had some time to spare, so:
The problem is the setter for the CollectionView property in the style for AnagramPagedItemsControl in generic.xaml.
This does not instantiate a new ListBox every time the style is applied; it will just create the one ListBox, the first time the style is created, and use that value over, and over again. So in effect, every instance of MainWindow shares the same ListBox.
You can see this by setting the Tag property of PART_CollectionView to (for instance) "1" in SetupBindings(ItemsControl PART_CollectionView). When you open a new window, you'll see that PART_CollectionView.Tag contains the same value you previously assigned.

C# WPF radio buttons split onto different pages

I'm working on WPF (XAML) using the designer (very newbie) and C# as backing code.
I need to be able to have a few "pages" of Radio Buttons in the same group (i.e. clicking on item A on page 1 then clicking on B on page 2 should deselect A on page 1).
How would I go about doing this?
Thank you!
Note that the "buttons" are actually just radio buttons above images.
First, I would NOT recommend doing this. As a user, I would be very confused/surprised if my selections on one page affected a selection on a previous one.
As to how to accomplish it, I will assume you are using MVVM (as you should be in WPF). First, the ViewModel for each page needs to have a reference to the same backing property in the Model. In other words, your Model has a property like (where MyRadioSelection is some enum you are binding to):
public MyRadioSelection GlobalSelection {get; set;}
and your view models have:
public MyRadioSelection UserSelection
{
get {return Model.GlobalSelection;}
set
{
Model.GlobalSelection = value;
OnPropertyChanged(UserSelection);
}
}
Then you just need a ValueEquals converter (from this answer), bind all your radio buttons to the enum, and you should be good to go!
Please let me know if you would like a piece explained further. Also, posting your existing code would help improve this answer. Also note that your Model may need some way of notifying the ViewModels of external (another ViewModel's) changes to the backing property. You could approach this from several directions, but just implementing INotifyPropertyChanged and listening to it in the ViewModel would work.

How do I keep the selection in ListBox when reloading ItemsSource

I am experimenting with WPF and MVVM in our system. However iam having a problem with keeping things selected in lists using only MVVM ( without doing extra CollectionViews ).
What i currently have is the list
ObservableCollection<ReservationCustomerList> Customers;
And then a property storing the selected Customer
ReservationCustomerList SelectedCustomer;
In my opinion now, when the list reloads (actually from another thread async), the selection should be able to be kept, however this does not happen.
Does someone have a nice clean way of achieving this ?
The way we did it was that we did not replace the collection. We added/removed the entries and updated existing entries if required. This maintains the selection.
You can use LINQ methods like Except to identify items that are new or removed.
In case the reloaded list still contains the last selected item and you want that item to be selected, then you can raise the PropertyChange event for the property SelectedCustomer after your collection gets reloaded.
Please make your sure your viewmodel class implements INotifyPropertyChanged interface.
you can use the ICollectionView to select the entity you want.
ICollectionview view = (ICollectionView)CollectionViewSource.GetDefaultView(this.Customers);
view.MoveCurrentTo(SelectedCustomer);
in your Xaml the itemsControl must have IsSynchronizedWithCurrentItem=true
or if the ItemsControl has a SelectedItem property you can simply bind it to your SelectedCustomer Property.
When you "reload" your collection you basically replace all values in it with new values. Even those that look and feel identical are in fact new items. So how do you want to reference the same item in the list when it is gone? You could certainly use a hack where you determine the item that was selected by its properties and reselect it (i.e. do a LINQ search through the list and return the ID of the matching item, then reselect it). But that would certainly not be using best practices.
You should really only update your collection, that is remove invalid entried and add new entries. If you have a view connected to your collection all the sorting and selecting and whatnot will be done automagically behind the scenes again.
Edit:
var tmp = this.listBox1.SelectedValue;
this._customers.Clear();
this._customers.Add(item1); this._customers.Add(item2);
this._customers.Add(item3); this._customers.Add(item4);
this.listBox1.SelectedValue = tmp;
in the method that does the reset/clear works for me. I.e. that is the code I put into the event handling method called when pressing the refresh button in my sample app. That way you dont even need to keep references to the customer objects as long as you make sure that whatever your ID is is consistent. Other things I have tried, like overwriting the collections ´ClearItems()´ method and overwriting ´Equals()´ and ´GetHashCode()´ didn't work - as I expected.

Categories

Resources