There are several approaches that can work; which is best may depend upon the speed and reliability of the communications protocol, the nature of the operations, and the extent to which use of the program will "flow" better if users wait for each request to complete before proceeding to the next, enter requests as fast as they wish and have the program handle them as fast as it can, or have users enter all requests and then process them as a group.
If you want the user interface to wait while each operation is performed, then having methods which simply perform operations directly but don't keep any state may be the simplest way of going about it. Such an approach is simple, and generally makes it easy to tell what's going on. If the remote end of the connection has a few important aspects of state which affect the way communications will be performed (e.g. communications mode settings, or packet sequence numbers), it may be helpful to have the class manage those aspects of state itself, but aspects of state other than communication should be managed by client code.
An alternative design is to have "read all state" and "write all state" methods, and have the UI flow entail loading state from a device or opting to create new state, editing the state without involving the device, and then storing the state to the device once editing is complete. This approach will minimize the number of times a user will have to wait for the device, consolidating all delays into one wait at the beginning and one at the end. The one limitation with this approach is that the user won't be able to see the effect of any changes on the remote device until the "apply" button is pressed (since no changes will actually be made until then). Whether that's a good or bad thing will depend upon the nature of the device.
A final approach is to keep two main sets of state--what the device has last reported, and what changes (if any) have been requested but not yet applied; along with that one may wish to keep track of how many unsuccessful attempts have been made to perform various operations. One might for each device property display a read-only and editable field next to each other. A background task should scan the properties and determine what things need updating on either the screen or in the device, and perform any updates as it notices them. I would suggest having the read-only text boxes implemented with a custom type with a method that can set the text at any time from any thread. The method should immediately set a private variable to the new text and
UpdateText method when no update request is already pending. If multiple requests are made to set the text before the UI thread has started processing the first one, the repeated operations should not generate multiple
BeginInvoke calls. Instead, the later operations should simply change the string which will get shown when the
UpdateText method finally starts executing.
An important thing to bear in mind is that while the actual properties of the physical device and the desired properties would ideally be one and the same, they are separate aspects of state and should probably be both maintained and (especially with the third approach) displayed as such. If for whatever reason, reading back the device state after setting it doesn't yield the new value, code should be prepared to convey that information to the user. The user might be confused as to why the value isn't updating, but will probably be less confused than if software suggests that the device holds the new value but it really doesn't.