Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Mr Shiny Pants
Nov 12, 2012

Ciaphas posted:

Alright, I've completely lost the plot. If binding directly to model properties through the view is bad juju (because it embeds knowledge of the model's internals into the view), and therefore have to have the view bind to viewmodel properties through which the actual data model is updated... then why do model classes exist at all in MVVM?

:saddowns:

It is fine, just not for his (Crashdome) particular use case.

Adbot
ADBOT LOVES YOU

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


I'm gonna drag my code from up-page down here, with modifications that worked to get the ListBox updated the moment one of the TextBoxes changed.

The ListBox updates correctly whenever one of the TextBoxes change. The label below it does not, because SelectedModel isn't changing--only its components, which is what the ListBox uses for rendering.

The MultiBinding works perfectly, in other words, but it means the View now knows exactly what the Model looks like (or at least enough of it to render), so if the definition of Model were to change, the View would break quietly. I have no idea if this is bad practice, or just something to deal with.

As is, the Label doesn't update--but it WOULD, if I could somehow draw a "SelectedModel component changed->SelectedModel changed->RaisePropertyChanged("SelectedModel")" connection. The answer here seems to be properties like public string CurA and CurB in the ViewModel, whose setters change SelectedModel and call RaisePropertyChanged on it. This makes me wonder why the Model exists at all, if I'm just reimplementing its definition and interface in the ViewModel.

I understand why this is, I just don't understand which way is correct.

(edit) throwing in some bold on the stuff I'm confused and frustrated by

C# code:
class Model
{
  public string A {get; set;}
  public string B {get; set;}

  public override ToString() { return A + "," + B; }
}
C# code:
class ViewModel : ViewModelBase // INotifyPropertyChanged -- SetField() mainly	 
{
  public ViewModel()
  {
    Models = new ObservableCollection<Model>();
    Models.Add(new Model { A = "123", B = "abc" });
    Models.Add(new Model { A = "456", B = "def" });
  }

  public ObservableCollection<Model> Models {get; set;}
  Model _SelectedModel;
  public Model SelectedModel
  {
    get { return _SelectedModel; }
    set { SetField(ref _SelectedModel, value); IsModelSelected = value != null; }
  }

  bool _IsModelSelected;
  public bool IsModelSelected
  {
    get { return _IsModelSelected; }
    set { SetField(ref _IsModelSelected, value); }
  }

  public RelayCommand AddCommand
  {
    get
    {
      return new RelayCommand(x =>
      {
        Model m = new Model();
        Models.Add(m);
        SelectedModel = m;
      });
    }
  }
}
XML code:
<Window ...>
  <StackPanel>
    <Button Content="Add New" Command="{Binding AddCommand}" />
    <ListBox Height="100" ItemsSource="{Binding Models}" SelectedItem="{Binding SelectedModel}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock>
            <TextBlock.Text>
             <MultiBinding StringFormat="{}{0},{1}">
               <Binding Path="A" />
               <Binding Path="B" />
             </MultiBinding>
            </TextBlock.Text>
          </TextBlock>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
    <TextBox Text="{Binding SelectedModel.A, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsModelSelected}" />
    <TextBox Text="{Binding SelectedModel.B, UpdateSourceTrigger=PropertyChanged}" IsEnabled="{Binding IsModelSelected}" />
  </StackPanel>
</Window>

Ciaphas fucked around with this message at 01:04 on Aug 6, 2015

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Oh and there's one more bit of fun that's making me tear my hair out. That Label that's not updating when one of the TextBoxes changes? If I change that to a TextBlock instead nad bind to Text (instead of Content, since Content doesn't exist), it works perfectly. :tizzy:

I'm spending half my time lost in how MVVM is supposed to be done, half in how the hell binding in WPF works for some controls and differently for others, and all my time losing my goddamned mind. :cry:

raminasi
Jan 25, 2005

a last drink with no ice

Ciaphas posted:

Alright, I've completely lost the plot. If binding directly to model properties through the view is bad juju (because it embeds knowledge of the model's internals into the view), and therefore have to have the view bind to viewmodel properties through which the actual data model is updated... then why do model classes exist at all in MVVM?

:saddowns:

Because you don't want your model relying on your view any more than you want your view relying on your model. Your model is the thing you burp into a database or fart out over a network connection; everything that exists so that a view can use it is superfluous.

e: You do know that TextBox updates rely on logical focus and not keyboard focus, right? That may be confounding all of this.

raminasi fucked around with this message at 21:15 on Aug 5, 2015

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


GrumpyDoctor posted:

e: You do know that TextBoxe updates rely on logical focus and not keyboard focus, right? That may be confounding all of this.

I do, yeah, I make sure to click away from the TextBox I'm editing (usually to the other one) when I'm testing things.

GoodCleanFun
Jan 28, 2004

Ciaphas posted:

Alright, I've completely lost the plot. If binding directly to model properties through the view is bad juju (because it embeds knowledge of the model's internals into the view), and therefore have to have the view bind to viewmodel properties through which the actual data model is updated... then why do model classes exist at all in MVVM?

:saddowns:

Business rules and logic.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

GoodCleanFun posted:

Business rules and logic.

And then someone like me comes along -- I dislike heavy models. Models should have practically no logic in them.

crashdome
Jun 28, 2011

Ciaphas posted:

Alright, I've completely lost the plot. If binding directly to model properties through the view is bad juju...

:ssh:
It's not!

raminasi
Jan 25, 2005

a last drink with no ice

Ciaphas posted:

Oh and there's one more bit of fun that's making me tear my hair out. That Label that's not updating when one of the TextBoxes changes? If I change that to a TextBlock instead nad bind to Text (instead of Content, since Content doesn't exist), it works perfectly. :tizzy:

Well, sure. TextBlock.Text knows it needs to stringify what it's bound to, but Label.Content can be any old thing so it has no idea how to display a Model.

A useful thing for WPF debugging is binding diagnostics: If you include a particular namespace somewhere:
code:
xmlns:diag="clr-namespace:System.Diagnostics;assembly=WindowsBase"
Then you can trace your bindings:
code:
{Binding Path=Whatever, diag:PresentationTraceSources.TraceLevel=High}
Which will vomit a whole bunch of stuff into your Output window when you have a debugger attached.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Ithaqua posted:

And then someone like me comes along -- I dislike heavy models. Models should have practically no logic in them.

I think we all have a different idea of what "Model" means. My interpretation of MVVM is:

View: XAML and code-behind (limited use of code-behind, really onlyfor handling specific events)
ViewModel: The in-code representation of your UI, i.e. all data and interaction but no presentation
Model: Every single other part of your application not view-related

All UI related things happen through the View and ViewModel. The Model is, collectively, your services and repositories and caches and whatever the hell else makes your application do actual stuff.

Mr Shiny Pants
Nov 12, 2012
Something like this:

code:
class Model
    {
      public string A {get; set;}
      public string B {get; set;}
    }

    public class ViewModel
    {
        public Model Model {get;set;}
        public string A 
        {
            get{return Model.A;}
            set{Model.A = value;
                INotifyPropertyChanged();
            }
        }
        public string B 
        {
            get{return Model.B;}
            set{Model.B = value;
                INotifyPropertyChanged();
            }
        }

        public string Concated
        {
            get{return String.Format("{0},{1}",Model.A,Model.B);}
        }
        public ViewModel(Model model)
        {
            Model = model;
        }
    }

C# code:

    class ViewModels : ViewModelBase // INotifyPropertyChanged -- SetField() mainly	 
    {
      public ViewModels()
      {
        ViewModels = new ObservableCollection<ViewModel>();
        ViewModels.Add(new ViewModel(new Model { A = "123", B = "abc" }));
        ViewModels.Add(new ViewModel(new Model { A = "456", B = "def" }));
      }
    
      public ObservableCollection<Model> ViewModels {get; set;}
      ViewModel _selectedViewModel;
      public ViewModel SelectedViewModel
      {
        get { return _selectedViewModel; }
        set { _selectedViewModel = value;
              NotifyPropertyChanged();
            }
      }
    
      public bool IsViewModelSelected()
      {
          if(_selectedViewModel != null)
          {
              return true;
          }
          return false;
      }


    
      public RelayCommand AddCommand
      {
        get
        {
          return new RelayCommand(x =>
          {
            Model m = new Model();
            Models.Add(m);
            SelectedViewModel = m;
          });
        }
      }
    }


<Window ...>
  <StackPanel>
    <Button Content="Add New" Command="{Binding AddCommand}" />
    <ListBox Height="100" ItemsSource="{Binding ViewModels}" SelectedItem="{Binding SelectedViewModel}">
      <ListBox.ItemTemplate>
        <DataTemplate>
          <TextBlock Text="{Binding Concated}"/>
        </DataTemplate>
      </ListBox.ItemTemplate>
    </ListBox>
    <TextBox Text="{Binding SelectedViewModel.A}" IsEnabled="{Binding IsViewModelSelected}" />
    <TextBox Text="{Binding SelectedViewModel.B}" IsEnabled="{Binding IsViewModelSelected}" />
    <Label Content="{Binding SelectedViewModel}"/>
  </StackPanel>
</Window>
I might have missed a couple of things.

Mr Shiny Pants fucked around with this message at 21:50 on Aug 5, 2015

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:



Then I guess this is ultimately what the discussion--and my questions--are really about.

I'm like this close to just writing whatever the gently caress works first and leaving future consequences to the next rear end in a top hat in line after me, like every other programmer before me at this loving place.

crashdome
Jun 28, 2011
I think the crux of the debate is: Should the View not have any reliance on the Model?

Bognar states what most people on the Internet do - that The View and Model are completely separated.

I cannot, for the life of me, find any evidence to suggest the reasoning behind that. Your VM will have a tie to the Model. Your View has a tie to the ViewModel. The purpose is so the Model is alleviated from any View specific code. It is not incorrect to say that "A View can be tied to a Model (e.g. through a ViewModel binding) and the Model is still left without any UI/View specific code"

Unless you consider INPC as "View specific" - which I do not. At least not any more so than a String is View specific.

You can certainly work towards keeping your Model as far away from a View as possible but, in smaller applications it introduces a shitton of extra code for very little reward.

GoodCleanFun
Jan 28, 2004

Ithaqua posted:

And then someone like me comes along -- I dislike heavy models. Models should have practically no logic in them.

I agree with Bognar's response above. The viewModel provides what's needed to represent the state of the view. Models living in the viewModel provide that data. A model may be something strictly lightweight for the viewModel as you suggest or may provide access to various database operations. In some cases I think it makes sense for models to do double duty and perform both functions.

Where do you do the majority of the actual work an application does?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Mr Shiny Pants posted:

Something like this:

<code elided>

I might have missed a couple of things.

Now I'm even MORE confused. You have a separate ViewModel class wrapping around each Model, and you're binding to an ObservableCollection of THOSE instead of the Model objects themselves? What does that accomplish?

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


I hope no one minds if I try a slightly different tack to try to get this squared in my head.

The code in my post at the top of the page, aside from the elisions in the <Window> tag, does exactly what I want for the purposes of understanding what's up. I can edit the values in the TextBoxes, and see the corresponding entry in the ListBox update as I type, because the back-end SelectedModel is having its properties updated.
  • What would I change to make this program work exactly the same way, without binding directly to the selected model object's properties from the view (i.e. if I was not allowed to bind to SelectedModel.A or SelectedModel.B from the view)? In other words, how would I remove all knowledge of the Model's exact contents from the View? (I'm aware that I'd still, effectively, have to edit an A and B property in the ViewModel, but that's still not the same as directly editing the Model. I just don't know how to do up these proxy properties such that everything else appears to be updated automatically.)
  • Would I even ever want to do this from an MVVM purist point of view or am I totally up the wrong tree? (Normally I don't give a poo poo about being completely purist about anything, but I need to know the rules before I can confidently break them.)
(edit) I'm really sorry for being annoying about this, I know I'm getting more frustrated than this poo poo is frankly worth. :(

(edit again: wait, I just realized, how is the binding in the ListView being notified that its bound values--SelectedModel.A and B--have been changed when Model doesn't implement INPC huglaghlaghgahg im so lost:cry:)

Ciaphas fucked around with this message at 01:21 on Aug 6, 2015

putin is a cunt
Apr 5, 2007

BOY DO I SURE ENJOY TRASH. THERE'S NOTHING MORE I LOVE THAN TO SIT DOWN IN FRONT OF THE BIG SCREEN AND EAT A BIIIIG STEAMY BOWL OF SHIT. WARNER BROS CAN COME OVER TO MY HOUSE AND ASSFUCK MY MOM WHILE I WATCH AND I WOULD CERTIFY IT FRESH, NO QUESTION

crashdome posted:

I think the crux of the debate is: Should the View not have any reliance on the Model?

Bognar states what most people on the Internet do - that The View and Model are completely separated.

I cannot, for the life of me, find any evidence to suggest the reasoning behind that. Your VM will have a tie to the Model. Your View has a tie to the ViewModel. The purpose is so the Model is alleviated from any View specific code. It is not incorrect to say that "A View can be tied to a Model (e.g. through a ViewModel binding) and the Model is still left without any UI/View specific code"

Unless you consider INPC as "View specific" - which I do not. At least not any more so than a String is View specific.

You can certainly work towards keeping your Model as far away from a View as possible but, in smaller applications it introduces a shitton of extra code for very little reward.

I have no disagreement with this and I tend to do something like what you're talking about. I have a ViewModel that pulls together the various models that are required for a View. For example, viewing a user's profile page might necessitate a ViewModel that can supply all of the user's profile details as well as a list of their most recent posts or something. In this case my ViewModel would have a User User property containing the actual User model and a List<Post> Posts property containing a list of actual Post models. Is this right? I'm not sure I care. It's plainly obvious and easy to understand for anyone else coming to the project and adding a new property to a Model just means adding it in the one place and then adding a display for it in the View. I guess I look at my ViewModels as a handy shortcut to get to the Models I need for the view.

That said, I work with MVC not MVVM so I might be talking on a completely different topic - I have no familiarity with MVVM so the techniques/approaches might not be as similar as I'm imagining them to be.

Ciaphas posted:

(edit) I'm really sorry for being annoying about this, I know I'm getting more frustrated than this poo poo is frankly worth. :(

Trust me when I say we've all been there - each and every one of us has "that one topic" that drives us nuts until we can wrap our heads around it. Don't lose heart :)

putin is a cunt fucked around with this message at 01:15 on Aug 6, 2015

putin is a cunt
Apr 5, 2007

BOY DO I SURE ENJOY TRASH. THERE'S NOTHING MORE I LOVE THAN TO SIT DOWN IN FRONT OF THE BIG SCREEN AND EAT A BIIIIG STEAMY BOWL OF SHIT. WARNER BROS CAN COME OVER TO MY HOUSE AND ASSFUCK MY MOM WHILE I WATCH AND I WOULD CERTIFY IT FRESH, NO QUESTION

Gul Banana posted:

i wasn't very clear before due to phoneposting, but mr. shiny pants has it right. there's nothing wrong with "just some endpoints where you can get stuff over HTTP" though- the implication is that it then doesn't matter much what the Right Way is, because it's whatever you make up.

people sometimes talk about "levels" of REST these days, which are like
level 1 - you're using http methods and json
level 2 - the api is oriented around resources rather than calls
level 3 - client application state transitions via discovered hypermedia

each brings you closer to a model which is in theory highly scalable, evolvable, etc, but is not actually necessary, particularly if you have only a single client and server.

Thanks for this - level 2 is really what I'm aiming for. I've realised from this discussion that a by-the-book "RESTful" API is not my goal as I first thought, I just want a resource-based API that receives and sends JSON data in a logical manner. With that in mind I'll continue to follow the request/response class pattern so that it's consistent and I'll just make sure I document that pattern thoroughly for any future devs.

SirViver
Oct 22, 2008

ljw1004 posted:

Oh dear! If you have time,

SirViver posted:

Welp, sent two reports for this a few minutes ago after I had managed to reproduce it, but of course, once I start the recording tool and open the dialog it magically works :(

I'll see if I can properly reproduce it later, I hope you don't mind the duplicate reports - I tag all of them with the attention thing you mentioned.

E: Also sent a report regarding the EnC hang.
I've finally managed to reproduce and record the New Project dialog hang. It was unresponsive for nearly two minutes, at least with the recording tool running. Visual Studio even popped up the "VS is busy" tray notification twice during the wait. I hope this helps narrow down the possible cause for such hangs.

Oh and by the way, if anyone's wondering, you can actually recolor the collapsed text region blocks with the "Collapsed Text (Collapsed)" display item - something I had tried before - but unlike most other color options you have to for some reason restart Visual Studio for it to take effect.

raminasi
Jan 25, 2005

a last drink with no ice

Ciaphas posted:

What would I change to make this program work exactly the same way, without binding directly to the selected model object's properties from the view (i.e. if I was not allowed to bind to SelectedModel.A or SelectedModel.B from the view)? In other words, how would I remove all knowledge of the Model's exact contents from the View? (I'm aware that I'd still, effectively, have to edit an A and B property in the ViewModel, but that's still not the same as directly editing the Model. I just don't know how to do up these proxy properties such that everything else appears to be updated automatically.)

One way to do it would be what Mr Shiny Pants did: wrap each Model in its own miniature view model. For such lightweight models, this is probably not worth it.

Another way to do it would be to create AOfSelected and BOfSelected properties in your ViewModel; when they're changed, the underlying A and B properties of the selected Model are changed as well. The annoying part is going the other way: what if something else changes one of those underlying properties, or switches the selected Model itself? In the latter case, presuming the only way to change the selection is through this view you're creating, you can just cause the SelectedModel setter to additional fire PropertyChanged with "AOfSelected" and "BOfSelected", or with an empty string. (Both choices suck, for different reasons.) In the former case, where something external is allowed to fiddle with Models, you either need to implement INPC on the Models themselves or provide a facility for external components to notify your ViewModel that it needs to update itself. (I used to lean towards the first solution, but now I lean towards the second.)

Is it worth it? Well, as always, that depends. Fortunately, it's basically the same tradeoff involved in every layer of abstraction: Will putting more scaffolding in now save you time later? If your actual problem is as simple as your example, I'd just throw INPC on the Models and call it a day.

This is WPF: It makes hard problems easy and easy problems hard.

Che Delilas
Nov 23, 2009
FREE TIBET WEED

Ciaphas posted:

I hope no one minds if I try a slightly different tack to try to get this squared in my head.

The code in my post at the top of the page, aside from the elisions in the <Window> tag, does exactly what I want for the purposes of understanding what's up. I can edit the values in the TextBoxes, and see the corresponding entry in the ListBox update as I type, because the back-end SelectedModel is having its properties updated.
  • What would I change to make this program work exactly the same way, without binding directly to the selected model object's properties from the view (i.e. if I was not allowed to bind to SelectedModel.A or SelectedModel.B from the view)? In other words, how would I remove all knowledge of the Model's exact contents from the View? (I'm aware that I'd still, effectively, have to edit an A and B property in the ViewModel, but that's still not the same as directly editing the Model. I just don't know how to do up these proxy properties such that everything else appears to be updated automatically.)
  • Would I even ever want to do this from an MVVM purist point of view or am I totally up the wrong tree? (Normally I don't give a poo poo about being completely purist about anything, but I need to know the rules before I can confidently break them.)
(edit) I'm really sorry for being annoying about this, I know I'm getting more frustrated than this poo poo is frankly worth. :(

(edit again: wait, I just realized, how is the binding in the ListView being notified that its bound values--SelectedModel.A and B--have been changed when Model doesn't implement INPC huglaghlaghgahg im so lost:cry:)

The short answer to your first question is that you create intermediary classes (with INPC on them) for the ViewModel to data bind with the View. These intermediary classes will contain only the data from the Model that the View needs for UI purposes. When INPC fires on any of this stuff, the ViewModel will then call any methods on the Model that need to be called, whether that just be the Setters to update the Model, or something more complex.

Would you ever want to do this? Sure. But I will call your attention to Bognar's post:

Bognar posted:

I think we all have a different idea of what "Model" means. My interpretation of MVVM is:

View: XAML and code-behind (limited use of code-behind, really onlyfor handling specific events)
ViewModel: The in-code representation of your UI, i.e. all data and interaction but no presentation
Model: Every single other part of your application not view-related

All UI related things happen through the View and ViewModel. The Model is, collectively, your services and repositories and caches and whatever the hell else makes your application do actual stuff.

In your example, you've got a very, very simple class with some data that the View needs, and you're calling it the Model. That's okay, most MVVM tutorials and discussion does this for the sake of focusing on the MVVM pattern. But in the real world, your "Model" is not just a bunch of simple data containers; it's all the business rules and logic and database access and web service calls and math that your application does. The View/ViewModel are just the means for your users to interact with all of it. In this world, what you called your Model class would probably be what I called the intermediary class, and the ViewModel would be responsible for instantiating it (probably after calling a bunch of other methods in other classes to get the data it needs to construct that Model object in the first place).

But if all there is to your model is an in-memory collection of POCO objects, there's no real reason not to just slap INPC on your "Model" class and data bind directly. You don't need to add a layer of complexity (intermediate classes) for no reason.

chippy
Aug 16, 2006

OK I DON'T GET IT
Really stupid question incoming, but it's the end of the day and I'm tired and started off with a hangover.

WinForms: I just want a property of the form (very simple dialogue for entering a single number) to always reflect the value of a NumericUpDown in the form. I figured I'd use data binding (which I only fairly recently discovered) instead of my usual manual approach, so I did this in the constructor of the form:

code:
hoursNumericUpDown.DataBindings.Add(New Binding("Value", Me, "HoursWorked"))
Doesn't work. HoursWorked stays at 0.0 whatever happens.

What's the way to do this? It shouldn't be too hard, surely? I don't have to use a binding source just for a single value like this do I?

chippy fucked around with this message at 17:53 on Aug 6, 2015

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Thanks for all the explanations. I feel like I'm a bit closer to getting it.

My real-world model, in the case of this page of the app (it's a tabbed-wizard sort of interface), is a class called TimeSegment, essentially a nanosecond-precision TimeSpan (not actually using TimeSpan, just illustrating. Probably could have been one though, but I didn't write it) with a bunch of extra cruft for parsing input strings/binary data into the correct start and end times. These end times--split into year, day, hour, minute, second, and second fractions (up to nine digits thereof, as I said)--are what my view needs to be able to edit. So probably a dozen properties that need UI exposure, and another dozen or so besides that for business logic. A dozen UI-exposed properties isn't a lot, I know, but it still made me leery of whether I really needed proxy properties in the VM or not, and what I would gain from doing so (which I'm still not wholly sure about). At least nothing external to the application can change the TimeSegments in question, just the application itself, so that simplifies the scenario slightly.

The UI's essentially the same as my example though: a list of currently read-in and added TimeSegments, add/remove buttons, and TextBoxes and spinners for manipulating the parts of the selected TimeSegment.

As you said, I could probably slap INPC on the TimeSegment class, have the view bind directly to those properties rather than proxies in the view's one TimeSegmentViewModel, and call it good. I wanted to practice and make sure I understand why and when to go full bore on the pattern, however, which is what prompted all this.

NihilCredo
Jun 6, 2011

iram omni possibili modo preme:
plus una illa te diffamabit, quam multæ virtutes commendabunt

chippy posted:

WinForms: I just want a property of the form (very simple dialogue for entering a single number) to always reflect the value of a NumericUpDown in the form.

Based on those specs, is there any reason you can't just write

code:
public readonly property HoursWorked as integer
if hoursNumericUpDown is nothing then return 0 else return hoursNumericUpDown.Value
end property
instead of using WinForms's lovely stringly typed databinding?

(If you do need to use databinding, VB14's NameOf function should at least help with type-safety.)

NihilCredo fucked around with this message at 19:41 on Aug 6, 2015

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Here's a new, more specific question. How do you handle dependent/calculated properties, in your viewmodel, that are bound?

Take the example below. Assume I have a view that binds a textblock or something to TotalCost:
C# code:
class MyVM : MyVMBase // INPC
{
  private double _Price;
  public double Price
  {
    get { return _Price; }
    set
    {
      SetField(ref _Price, value);
      RaisePropertyChanged("TotalCost');
    }
  }
  private double _Tax;
  public double Tax
  {
    get { return _Tax; }
    set
    {
      SetField(ref _Tax, value);
      RaisePropertyChanged("TotalCost');
    }
  }

  public double TotalCost
  {
    get { return Price + (Price * Tax); }
  }
}
With those extra RaisePropertyChanged calls, the UI updates whenever Price or Tax changes. This works in this small case but it strikes me that having to change every other property that a calculated property depends on would become a maintenance nightmare in a real hurry. (And, logically, why should Price or Tax have to know about TotalCost when really TotalCost already explicitly states that it needs to know about Price and Tax?) Is there any nice way to keep the basic properties simple (remove the extra RaisePropertyChanged() calls) while still keeping the UI up to date?

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
Fody.PropertyChanged is a pretty neat way of automatically managing INPC calls. I don't use it because I tend to avoid "magic" where possible, but I know people who have had success with it.

Otherwise, yeah I pretty much do exactly what you've got written above. In most cases, the UI doesn't get complicated enough that it's too hard to manage dependent properties. In cases where it does, I have helper methods like RaiseAllPropertiesChanged().

Also, you should use the C# 6 nameof operator to specify property names instead of strings.

Bognar fucked around with this message at 20:49 on Aug 6, 2015

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Unless C# 6 is usable in VS2013 and I just didn't notice, I don't think we're gonna have access to it for a very very long time. :( (Our code uses [CallerMemberName] in the function for self-notification, before anyone else mentions)

Fody.PropertyChanged looks neat, thanks, I'll poke at that too. If I'm lucky though, you're right and the dependent properties won't get complicated enough to do anything other than what's in my example.

Drastic Actions
Apr 7, 2009

FUCK YOU!
GET PUMPED!
Nap Ghost

Bognar posted:

Fody.PropertyChanged is a pretty neat way of automatically managing INPC calls. I don't use it because I tend to avoid "magic" where possible, but I know people who have had success with it.

Otherwise, yeah I pretty much do exactly what you've got written above. In most cases, the UI doesn't get complicated enough that it's too hard to manage dependent properties. In cases where it does, I have helper methods like RaiseAllPropertiesChanged().

Also, you should use the C# 6 nameof operator to specify property names instead of strings.

I used PropertyChanged in my Awful Forums Library PCL for a few entities (because I was lazy and didn't want to implement property changed events myself :v:). Works great and does what I expect.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Got another one.

XML code:
<!-- datacontext is my VM-->
<!--works the same with default UpdateSourceTrigger, just easier to see-->
<TextBox Text="{Binding MyValue.Value, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding MyValue.Value}"/>
C# code:
class VM
{
  public VM() { MyValue = new MyValueClass(); }
  public MyValueClass MyValue {get; set;}
}
class MyValueClass
{
  public string Value {get; set;}
}
MyValue's class doesn't implement INPC, and MyValue.Value isn't a dependency property. Despite this, the TextBlock is updating as I type in the TextBox. How is it getting the notification to update?

(ed) Is the compiler just somehow realizing "these two elements are bound to the same drat value, let's just bind them to each other instead" or something?

Ciaphas fucked around with this message at 23:38 on Aug 6, 2015

Che Delilas
Nov 23, 2009
FREE TIBET WEED

Ciaphas posted:

Got another one.

XML code:
<!-- datacontext is my VM-->
<!--works the same with default UpdateSourceTrigger, just easier to see-->
<TextBox Text="{Binding MyValue.Value, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Text="{Binding MyValue.Value}"/>
C# code:
class VM
{
  public VM() { MyValue = new MyValueClass(); }
  public MyValueClass MyValue {get; set;}
}
class MyValueClass
{
  public string Value {get; set;}
}
MyValue's class doesn't implement INPC, and MyValue.Value isn't a dependency property. Despite this, the TextBlock is updating as I type in the TextBox. How is it getting the notification to update?

(ed) Is the compiler just somehow realizing "these two elements are bound to the same drat value, let's just bind them to each other instead" or something?

http://stackoverflow.com/questions/7767218/why-does-the-binding-update-without-implementing-inotifypropertychanged

Short answer: It does bind to something automatically, under specific conditions, and it takes more resources to do it. If want those properties to update, it behooves you to put INPC on them.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Man I should have been able to find that on google. I gotta turn off that search history thing, it's mucking up my results with all the other MVVM crap I've searched for the past few weeks.

Thanks :shobon:

chippy
Aug 16, 2006

OK I DON'T GET IT

NihilCredo posted:

Based on those specs, is there any reason you can't just write

code:
public readonly property HoursWorked as integer
if hoursNumericUpDown is nothing then return 0 else return hoursNumericUpDown.Value
end property
instead of using WinForms's lovely stringly typed databinding?

(If you do need to use databinding, VB14's NameOf function should at least help with type-safety.)

Yeah gently caress it, that'll do. Cheers.

Uziel
Jun 28, 2004

Ask me about losing 200lbs, and becoming the Viking God of W&W.
I am curious how I can use a framework from Microsoft Research: Infer.NET (http://research.microsoft.com/en-us/um/cambridge/projects/infernet/) without running afoul of their licensing.

quote:

Can I use Infer.NET in a commercial application?

At this time, commercial use of Infer.NET is limited to Microsoft. No other commercial licenses are available.

I wanted to use it for an internal application that would reside on my company's intranet. Does anyone know if this would be "commercial" use? We wouldn't be selling software that included it, but the application would indirectly benefit customers.
For example, my use case is to help identify internal help desk tickets submitted by customer service representatives, and get them to the correct queues faster, resulting is better customer service.

New Yorp New Yorp
Jul 18, 2003

Only in Kenya.
Pillbug

Uziel posted:

I am curious how I can use a framework from Microsoft Research: Infer.NET (http://research.microsoft.com/en-us/um/cambridge/projects/infernet/) without running afoul of their licensing.


I wanted to use it for an internal application that would reside on my company's intranet. Does anyone know if this would be "commercial" use? We wouldn't be selling software that included it, but the application would indirectly benefit customers.
For example, my use case is to help identify internal help desk tickets submitted by customer service representatives, and get them to the correct queues faster, resulting is better customer service.

I'm not a lawyer, but yes. If you write software for a business, that's commercial use.

Ciaphas
Nov 20, 2005

> BEWARE, COWARD :ovr:


Bognar posted:

Fody.PropertyChanged is a pretty neat way of automatically managing INPC calls. I don't use it because I tend to avoid "magic" where possible, but I know people who have had success with it.

Otherwise, yeah I pretty much do exactly what you've got written above. In most cases, the UI doesn't get complicated enough that it's too hard to manage dependent properties. In cases where it does, I have helper methods like RaiseAllPropertiesChanged().

Also, you should use the C# 6 nameof operator to specify property names instead of strings.

I wanted to come back to this, because I had a sudden brainstorm yesterday about a nice elegant way to handle this situation without using Fody.PropertyChanged: attributes and reflection, so my VM ends up looking something like this:
C# code:
class VM : ObservableBase // INPC
{
  string _A;
  public string A
  {
    get { return _A; }
    set { SetField(ref _A, value); }
  }

  string _B;
  public string B
  {
    get { return _B; }
    set { SetField(ref _B, value); }
  }

  [INPCDepends("A", "B")] // nameof A, nameof B in C# 6 :(
  public string Combo
  {
    get { return A + "," + B; }
  }
}
INPCDependsAttribute is nothing but a list of what strings (property names) it was constructed with. On construction, ObservableBase reflects itself, building a dictionary of property names to the names of properties that specify that property as a dependency. So when RaisePropertyChanged gets called on A or B, it recursively gets called on Combo.

Haven't solved circular dependency detection or handling yet, but I was rather proud I managed to do this with zero knowledge of reflection and attributes going in. :shobon:

Anyway, opinion time: does this seem too "magical" to anyone? It seems like a nice logical way to keep a derived property and its notifications together, for future maintenance, but I'm open to dissent :v:

Ciaphas fucked around with this message at 23:07 on Aug 7, 2015

crashdome
Jun 28, 2011
I've always done it manually - as just adding another Raise call to the non-calculated properties. Having something there in the property setter reminds me that it affects other things when I come back to the code months later. If I have many calculated properties, I package them into a method on the class. I do, however very much like what you've done and may look into that in the future.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy

Ciaphas posted:

Haven't solved circular dependency detection or handling yet, but I was rather proud I managed to do this with zero knowledge of reflection and attributes going in. :shobon:

Anyway, opinion time: does this seem too "magical" to anyone? It seems like a nice logical way to keep a derived property and its notifications together, for future maintenance, but I'm open to dissent :v:

Good on you for working through the Reflection API with no prior knowledge. It's not always the easiest thing to use (or discover how to use), but you can do a lot of cool things with it. Next up, learn about expression parsing - there's a ton of cool stuff to do there as well.

As far as "magic" goes, go with what works for you. I tend to not like magic that is excessively hidden or by convention since it can be hard to figure out what's going, but what you've got is necessarily declared right next to the method so you can't really miss it. I'd be fine with it.

Bognar
Aug 4, 2011

I am the queen of France
Hot Rope Guy
Speaking of magic, reflection, and expressions... I did a thing. Some of you who work on front-end web projects (and especially those who use React) may have heard of Facebook's new client-side querying language GraphQL. A pretty good intro to that is here: http://facebook.github.io/react/blog/2015/05/01/graphql-introduction.html

Having experienced a lot of the pain points that they mention in that article, I thought their solution was pretty neat. Unfortunately, since we live in a .NET world and because Facebook runs mostly on Linux-based OSS, I didn't expect to see an implementation provided for the Windows or .NET world anytime soon. A month or so ago, they released the GraphQL specification (located here https://facebook.github.io/graphql/ ). I figured I'd use that to dive in and see if I could get a simple implementation up and running.

Notice that the GraphQL queries look very similar to how you might write an anonymous type selector in Entity Framework. Extremely similar. Theoretically, we could parse a GraphQL query and map it to an Expression that is then passed on to Entity Framework. So, that's exactly what I did:

https://github.com/ckimes89/ef-graphql

(Stealing from the README)

quote:

For a DbContext named MyContext with a User model in the database, add queries to the Schema like so:

C# code:
GraphQL<MyContext>.Schema.CreateQuery("users", db => db.Users, list: true);
GraphQL<MyContext>.Schema.CreateQuery("user", new { id = 0 },
    (db, args) => db.Users.Where(u => u.Id == args.id));
The first query returns all users in the database and has no arguments to supply. The second query returns a specific user, given an id in the arguments. To call these methods using GraphQL, use the static Execute method:

C# code:
var queryUsers = @"
  query users {
    id
    name
  }";

var users = GraphQL<MyContext>.Execute(queryUsers);
Console.WriteLine(JsonConvert.SerializeObject(users));

var queryUser = @"
  query user(id: 1) {
    id
    jeffsName : name
    account {
        id
    }
  }";

var user = GraphQL<MyContext>.Execute(queryUser);
Console.WriteLine(JsonConvert.SerializeObject(user));
The Execute method returns a nested Dictionary<string, object>, so it's mostly just useful for serializing to JSON.

Multiple users output:

JSON code:
{
  "data": {
    "users": [
      {
        "id": 1,
        "name": "Jeff"
      },
      {
        "id": 2,
        "name": "Joe"
      }
    ]
  }
}
Single user output:

JSON code:
{
  "data": {
    "user": {
      "id": 1,
      "jeffsName": "Jeff",
      "account": {
        "id": 1000
      }
    }
  }
}

You can define queries on the schema using an arbitrary number of parameters as arguments. Parsing of the query is done in F# using FParsec, which is a port of the awesome Haskell library Parsec that's used for building parsers. From there, we map the parsed query to a query in the schema, then use the fields from the parsed query to build up a selector expression. Right now, this is all coded around using Entity Framework, but halfway through I realized it could pretty easily be built solely around IQueryable, so you could use any .NET ORM (or even query in-memory). I think that's going to be next on my list of things to do. There's a lot of work that needs to be done, though... this only superficially implements the spec and leaves out a lot of things. I'm also going to have to think hard about how to handle some aspects of it, such as Fragments.

What do you guys think?

ShimaTetsuo
Sep 9, 2001

Maximus Quietus

Ciaphas posted:

Anyway, opinion time: does this seem too "magical" to anyone?

Easier option: use WinForms instead of WPF, and then it "just works" because some part of the binding is broken and it will actually reread all of your properties regardless of which one you raise the event for (maybe not always I don't remember).

Adbot
ADBOT LOVES YOU

mortarr
Apr 28, 2005

frozen meat at high speed

Bognar posted:

Speaking of magic, reflection, and expressions...
https://github.com/ckimes89/ef-graphql

What do you guys think?

That looks real interesting, like being able to use it would be pretty handy, but also implementing the spec itself looks like a sweet-as piece of work though. How far are you through the spec?

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply